From 070eca955c4af1248cb78a216463ff757a5dc511 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 25 Nov 2019 17:12:53 -0600 Subject: ibmvnic: Fix completion structure initialization Fix multiple calls to init_completion for device completion structures. Instead, initialize them during device probe and reinitialize them later as needed. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 0686ded7ad3a..e1ab2feeae53 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -176,7 +176,7 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, ltb->map_id = adapter->map_id; adapter->map_id++; - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); if (rc) { @@ -215,7 +215,7 @@ static int reset_long_term_buff(struct ibmvnic_adapter *adapter, memset(ltb->buff, 0, ltb->size); - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); if (rc) return rc; @@ -943,7 +943,7 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) if (adapter->vpd->buff) len = adapter->vpd->len; - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); crq.get_vpd_size.first = IBMVNIC_CRQ_CMD; crq.get_vpd_size.cmd = GET_VPD_SIZE; rc = ibmvnic_send_crq(adapter, &crq); @@ -1689,7 +1689,7 @@ static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr) crq.change_mac_addr.cmd = CHANGE_MAC_ADDR; ether_addr_copy(&crq.change_mac_addr.mac_addr[0], dev_addr); - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); rc = ibmvnic_send_crq(adapter, &crq); if (rc) { rc = -EIO; @@ -2316,7 +2316,7 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter) adapter->fallback.rx_entries = adapter->req_rx_add_entries_per_subcrq; adapter->fallback.tx_entries = adapter->req_tx_entries_per_subcrq; - init_completion(&adapter->reset_done); + reinit_completion(&adapter->reset_done); adapter->wait_for_reset = true; rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM); if (rc) @@ -2332,7 +2332,7 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter) adapter->desired.rx_entries = adapter->fallback.rx_entries; adapter->desired.tx_entries = adapter->fallback.tx_entries; - init_completion(&adapter->reset_done); + reinit_completion(&adapter->reset_done); adapter->wait_for_reset = true; rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM); if (rc) @@ -2603,7 +2603,7 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev, cpu_to_be32(sizeof(struct ibmvnic_statistics)); /* Wait for data to be written */ - init_completion(&adapter->stats_done); + reinit_completion(&adapter->stats_done); rc = ibmvnic_send_crq(adapter, &crq); if (rc) return; @@ -4408,7 +4408,7 @@ static int send_query_phys_parms(struct ibmvnic_adapter *adapter) memset(&crq, 0, sizeof(crq)); crq.query_phys_parms.first = IBMVNIC_CRQ_CMD; crq.query_phys_parms.cmd = QUERY_PHYS_PARMS; - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); rc = ibmvnic_send_crq(adapter, &crq); if (rc) return rc; @@ -4960,6 +4960,9 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) INIT_LIST_HEAD(&adapter->rwi_list); spin_lock_init(&adapter->rwi_lock); init_completion(&adapter->init_done); + init_completion(&adapter->fw_done); + init_completion(&adapter->reset_done); + init_completion(&adapter->stats_done); clear_bit(0, &adapter->resetting); do { -- cgit v1.2.3-59-g8ed1b From 2147e3d09e9ba6edc54b1b4bb7d8fc3cca96776b Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 25 Nov 2019 17:12:54 -0600 Subject: ibmvnic: Terminate waiting device threads after loss of service If we receive a notification that the device has been deactivated or removed, force a completion of all waiting threads. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index e1ab2feeae53..dc1b88116330 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -4505,6 +4505,15 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, case IBMVNIC_CRQ_XPORT_EVENT: netif_carrier_off(netdev); adapter->crq.active = false; + /* terminate any thread waiting for a response + * from the device + */ + if (!completion_done(&adapter->fw_done)) { + adapter->fw_done_rc = -EIO; + complete(&adapter->fw_done); + } + if (!completion_done(&adapter->stats_done)) + complete(&adapter->stats_done); if (test_bit(0, &adapter->resetting)) adapter->force_reset_recovery = true; if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) { -- cgit v1.2.3-59-g8ed1b From 476d96ca9cc59ad07dc452184880b635e4e29b06 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 25 Nov 2019 17:12:55 -0600 Subject: ibmvnic: Bound waits for device queries Create a wrapper for wait_for_completion calls with additional driver checks to ensure that the driver does not wait on a disabled device. In those cases or if the device does not respond in an extended amount of time, this will allow the driver an opportunity to recover. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 112 ++++++++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index dc1b88116330..4ff6a515c061 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -159,6 +159,40 @@ static long h_reg_sub_crq(unsigned long unit_address, unsigned long token, return rc; } +/** + * ibmvnic_wait_for_completion - Check device state and wait for completion + * @adapter: private device data + * @comp_done: completion structure to wait for + * @timeout: time to wait in milliseconds + * + * Wait for a completion signal or until the timeout limit is reached + * while checking that the device is still active. + */ +static int ibmvnic_wait_for_completion(struct ibmvnic_adapter *adapter, + struct completion *comp_done, + unsigned long timeout) +{ + struct net_device *netdev; + unsigned long div_timeout; + u8 retry; + + netdev = adapter->netdev; + retry = 5; + div_timeout = msecs_to_jiffies(timeout / retry); + while (true) { + if (!adapter->crq.active) { + netdev_err(netdev, "Device down!\n"); + return -ENODEV; + } + if (retry--) + break; + if (wait_for_completion_timeout(comp_done, div_timeout)) + return 0; + } + netdev_err(netdev, "Operation timed out.\n"); + return -ETIMEDOUT; +} + static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb, int size) { @@ -183,7 +217,15 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); return rc; } - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) { + dev_err(dev, + "Long term map request aborted or timed out,rc = %d\n", + rc); + dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); + return rc; + } if (adapter->fw_done_rc) { dev_err(dev, "Couldn't map long term buffer,rc = %d\n", @@ -211,6 +253,7 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter, static int reset_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb) { + struct device *dev = &adapter->vdev->dev; int rc; memset(ltb->buff, 0, ltb->size); @@ -219,10 +262,16 @@ static int reset_long_term_buff(struct ibmvnic_adapter *adapter, rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); if (rc) return rc; - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) { + dev_info(dev, + "Reset failed, long term map request timed out or aborted\n"); + return rc; + } if (adapter->fw_done_rc) { - dev_info(&adapter->vdev->dev, + dev_info(dev, "Reset failed, attempting to free and reallocate buffer\n"); free_long_term_buff(adapter, ltb); return alloc_long_term_buff(adapter, ltb, ltb->size); @@ -949,7 +998,12 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) rc = ibmvnic_send_crq(adapter, &crq); if (rc) return rc; - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) { + dev_err(dev, "Could not retrieve VPD size, rc = %d\n", rc); + return rc; + } if (!adapter->vpd->len) return -ENODATA; @@ -987,7 +1041,14 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) adapter->vpd->buff = NULL; return rc; } - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) { + dev_err(dev, "Unable to retrieve VPD, rc = %d\n", rc); + kfree(adapter->vpd->buff); + adapter->vpd->buff = NULL; + return rc; + } return 0; } @@ -1696,9 +1757,9 @@ static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr) goto err; } - wait_for_completion(&adapter->fw_done); + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); /* netdev->dev_addr is changed in handle_change_mac_rsp function */ - if (adapter->fw_done_rc) { + if (rc || adapter->fw_done_rc) { rc = -EIO; goto err; } @@ -2319,9 +2380,16 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter) reinit_completion(&adapter->reset_done); adapter->wait_for_reset = true; rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM); - if (rc) - return rc; - wait_for_completion(&adapter->reset_done); + + if (rc) { + ret = rc; + goto out; + } + rc = ibmvnic_wait_for_completion(adapter, &adapter->reset_done, 60000); + if (rc) { + ret = -ENODEV; + goto out; + } ret = 0; if (adapter->reset_done_rc) { @@ -2335,10 +2403,18 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter) reinit_completion(&adapter->reset_done); adapter->wait_for_reset = true; rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM); - if (rc) - return ret; - wait_for_completion(&adapter->reset_done); + if (rc) { + ret = rc; + goto out; + } + rc = ibmvnic_wait_for_completion(adapter, &adapter->reset_done, + 60000); + if (rc) { + ret = -ENODEV; + goto out; + } } +out: adapter->wait_for_reset = false; return ret; @@ -2607,7 +2683,9 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev, rc = ibmvnic_send_crq(adapter, &crq); if (rc) return; - wait_for_completion(&adapter->stats_done); + rc = ibmvnic_wait_for_completion(adapter, &adapter->stats_done, 10000); + if (rc) + return; for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++) data[i] = be64_to_cpu(IBMVNIC_GET_STAT(adapter, @@ -4412,7 +4490,11 @@ static int send_query_phys_parms(struct ibmvnic_adapter *adapter) rc = ibmvnic_send_crq(adapter, &crq); if (rc) return rc; - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) + return rc; + return adapter->fw_done_rc ? -EIO : 0; } -- cgit v1.2.3-59-g8ed1b From ff25dcb9a1492ecbe495de936765c7ff3441b601 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 25 Nov 2019 17:12:56 -0600 Subject: ibmvnic: Serialize device queries Provide some serialization for device CRQ commands and queries to ensure that the shared variable used for storing return codes is properly synchronized. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 54 ++++++++++++++++++++++++++++++++++---- drivers/net/ethernet/ibm/ibmvnic.h | 2 ++ 2 files changed, 51 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 4ff6a515c061..c90080781924 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -210,11 +210,14 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, ltb->map_id = adapter->map_id; adapter->map_id++; + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); if (rc) { dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); + mutex_unlock(&adapter->fw_lock); return rc; } @@ -224,6 +227,7 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, "Long term map request aborted or timed out,rc = %d\n", rc); dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); + mutex_unlock(&adapter->fw_lock); return rc; } @@ -231,8 +235,10 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, dev_err(dev, "Couldn't map long term buffer,rc = %d\n", adapter->fw_done_rc); dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); + mutex_unlock(&adapter->fw_lock); return -1; } + mutex_unlock(&adapter->fw_lock); return 0; } @@ -258,15 +264,21 @@ static int reset_long_term_buff(struct ibmvnic_adapter *adapter, memset(ltb->buff, 0, ltb->size); + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; + reinit_completion(&adapter->fw_done); rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); - if (rc) + if (rc) { + mutex_unlock(&adapter->fw_lock); return rc; + } rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); if (rc) { dev_info(dev, "Reset failed, long term map request timed out or aborted\n"); + mutex_unlock(&adapter->fw_lock); return rc; } @@ -274,8 +286,10 @@ static int reset_long_term_buff(struct ibmvnic_adapter *adapter, dev_info(dev, "Reset failed, attempting to free and reallocate buffer\n"); free_long_term_buff(adapter, ltb); + mutex_unlock(&adapter->fw_lock); return alloc_long_term_buff(adapter, ltb, ltb->size); } + mutex_unlock(&adapter->fw_lock); return 0; } @@ -992,18 +1006,25 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) if (adapter->vpd->buff) len = adapter->vpd->len; + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD; crq.get_vpd_size.cmd = GET_VPD_SIZE; rc = ibmvnic_send_crq(adapter, &crq); - if (rc) + if (rc) { + mutex_unlock(&adapter->fw_lock); return rc; + } rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); if (rc) { dev_err(dev, "Could not retrieve VPD size, rc = %d\n", rc); + mutex_unlock(&adapter->fw_lock); return rc; } + mutex_unlock(&adapter->fw_lock); if (!adapter->vpd->len) return -ENODATA; @@ -1030,7 +1051,10 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) return -ENOMEM; } + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); + crq.get_vpd.first = IBMVNIC_CRQ_CMD; crq.get_vpd.cmd = GET_VPD; crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr); @@ -1039,6 +1063,7 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) if (rc) { kfree(adapter->vpd->buff); adapter->vpd->buff = NULL; + mutex_unlock(&adapter->fw_lock); return rc; } @@ -1047,9 +1072,11 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) dev_err(dev, "Unable to retrieve VPD, rc = %d\n", rc); kfree(adapter->vpd->buff); adapter->vpd->buff = NULL; + mutex_unlock(&adapter->fw_lock); return rc; } + mutex_unlock(&adapter->fw_lock); return 0; } @@ -1750,10 +1777,14 @@ static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr) crq.change_mac_addr.cmd = CHANGE_MAC_ADDR; ether_addr_copy(&crq.change_mac_addr.mac_addr[0], dev_addr); + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); + rc = ibmvnic_send_crq(adapter, &crq); if (rc) { rc = -EIO; + mutex_unlock(&adapter->fw_lock); goto err; } @@ -1761,9 +1792,10 @@ static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr) /* netdev->dev_addr is changed in handle_change_mac_rsp function */ if (rc || adapter->fw_done_rc) { rc = -EIO; + mutex_unlock(&adapter->fw_lock); goto err; } - + mutex_unlock(&adapter->fw_lock); return 0; err: ether_addr_copy(adapter->mac_addr, netdev->dev_addr); @@ -4486,15 +4518,24 @@ static int send_query_phys_parms(struct ibmvnic_adapter *adapter) memset(&crq, 0, sizeof(crq)); crq.query_phys_parms.first = IBMVNIC_CRQ_CMD; crq.query_phys_parms.cmd = QUERY_PHYS_PARMS; + + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); + rc = ibmvnic_send_crq(adapter, &crq); - if (rc) + if (rc) { + mutex_unlock(&adapter->fw_lock); return rc; + } rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); - if (rc) + if (rc) { + mutex_unlock(&adapter->fw_lock); return rc; + } + mutex_unlock(&adapter->fw_lock); return adapter->fw_done_rc ? -EIO : 0; } @@ -5050,6 +5091,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) __ibmvnic_delayed_reset); INIT_LIST_HEAD(&adapter->rwi_list); spin_lock_init(&adapter->rwi_lock); + mutex_init(&adapter->fw_lock); init_completion(&adapter->init_done); init_completion(&adapter->fw_done); init_completion(&adapter->reset_done); @@ -5111,6 +5153,7 @@ ibmvnic_stats_fail: ibmvnic_init_fail: release_sub_crqs(adapter, 1); release_crq_queue(adapter); + mutex_destroy(&adapter->fw_lock); free_netdev(netdev); return rc; @@ -5135,6 +5178,7 @@ static int ibmvnic_remove(struct vio_dev *dev) adapter->state = VNIC_REMOVED; rtnl_unlock(); + mutex_destroy(&adapter->fw_lock); device_remove_file(&dev->dev, &dev_attr_failover); free_netdev(netdev); dev_set_drvdata(&dev->dev, NULL); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index ebc39248b334..60eccaf91b12 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1026,6 +1026,8 @@ struct ibmvnic_adapter { int init_done_rc; struct completion fw_done; + /* Used for serialization of device commands */ + struct mutex fw_lock; int fw_done_rc; struct completion reset_done; -- cgit v1.2.3-59-g8ed1b From 1d4a09dadbb9ea7baaf6be897d69020c729e7440 Mon Sep 17 00:00:00 2001 From: Phong Tran Date: Tue, 26 Nov 2019 20:54:12 +0700 Subject: net: hso: Fix -Wcast-function-type correct usage prototype of callback in tasklet_init(). Report by https://github.com/KSPP/linux/issues/20 Signed-off-by: Phong Tran Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 74849da031fa..ca827802f291 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1214,8 +1214,9 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) * This needs to be a tasklet otherwise we will * end up recursively calling this function. */ -static void hso_unthrottle_tasklet(struct hso_serial *serial) +static void hso_unthrottle_tasklet(unsigned long data) { + struct hso_serial *serial = (struct hso_serial *)data; unsigned long flags; spin_lock_irqsave(&serial->serial_lock, flags); @@ -1265,7 +1266,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) /* Force default termio settings */ _hso_serial_set_termios(tty, NULL); tasklet_init(&serial->unthrottle_tasklet, - (void (*)(unsigned long))hso_unthrottle_tasklet, + hso_unthrottle_tasklet, (unsigned long)serial); result = hso_start_serial_device(serial->parent, GFP_KERNEL); if (result) { -- cgit v1.2.3-59-g8ed1b From 2eb1d3f4bcae6c83943214ccb26968a48360db06 Mon Sep 17 00:00:00 2001 From: Phong Tran Date: Tue, 26 Nov 2019 20:54:13 +0700 Subject: net: usbnet: Fix -Wcast-function-type correct usage prototype of callback in tasklet_init(). Report by https://github.com/KSPP/linux/issues/20 Signed-off-by: Phong Tran Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index dde05e2fdc3e..30e511c2c8d0 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1573,6 +1573,13 @@ static void usbnet_bh (struct timer_list *t) } } +static void usbnet_bh_tasklet(unsigned long data) +{ + struct timer_list *t = (struct timer_list *)data; + + usbnet_bh(t); +} + /*------------------------------------------------------------------------- * @@ -1700,7 +1707,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); skb_queue_head_init(&dev->rxq_pause); - dev->bh.func = (void (*)(unsigned long))usbnet_bh; + dev->bh.func = usbnet_bh_tasklet; dev->bh.data = (unsigned long)&dev->delay; INIT_WORK (&dev->kevent, usbnet_deferred_kevent); init_usb_anchor(&dev->deferred); -- cgit v1.2.3-59-g8ed1b From 786c4a5372e11919b5ea010a7338bac9ef08c732 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 26 Nov 2019 08:38:56 -0600 Subject: net: phy: dp83869: Fix return paths to return proper values Fix the return paths for all I/O operations to ensure that the I/O completed successfully. Then pass the return to the caller for further processing Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") Reported-by: Andrew Lunn Signed-off-by: Dan Murphy Signed-off-by: David S. Miller --- drivers/net/phy/dp83869.c | 49 +++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 1c7a7c57dec3..93021904c5e4 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -151,13 +151,13 @@ static int dp83869_config_port_mirroring(struct phy_device *phydev) struct dp83869_private *dp83869 = phydev->priv; if (dp83869->port_mirroring == DP83869_PORT_MIRRORING_EN) - phy_set_bits_mmd(phydev, DP83869_DEVADDR, DP83869_GEN_CFG3, - DP83869_CFG3_PORT_MIRROR_EN); + return phy_set_bits_mmd(phydev, DP83869_DEVADDR, + DP83869_GEN_CFG3, + DP83869_CFG3_PORT_MIRROR_EN); else - phy_clear_bits_mmd(phydev, DP83869_DEVADDR, DP83869_GEN_CFG3, - DP83869_CFG3_PORT_MIRROR_EN); - - return 0; + return phy_clear_bits_mmd(phydev, DP83869_DEVADDR, + DP83869_GEN_CFG3, + DP83869_CFG3_PORT_MIRROR_EN); } #ifdef CONFIG_OF_MDIO @@ -204,7 +204,7 @@ static int dp83869_of_init(struct phy_device *phydev) &dp83869->tx_fifo_depth)) dp83869->tx_fifo_depth = DP83869_PHYCR_FIFO_DEPTH_4_B_NIB; - return 0; + return ret; } #else static int dp83869_of_init(struct phy_device *phydev) @@ -216,7 +216,7 @@ static int dp83869_of_init(struct phy_device *phydev) static int dp83869_configure_rgmii(struct phy_device *phydev, struct dp83869_private *dp83869) { - int ret, val; + int ret = 0, val; if (phy_interface_is_rgmii(phydev)) { val = phy_read(phydev, MII_DP83869_PHYCTRL); @@ -233,13 +233,13 @@ static int dp83869_configure_rgmii(struct phy_device *phydev, } if (dp83869->io_impedance >= 0) - phy_modify_mmd(phydev, DP83869_DEVADDR, - DP83869_IO_MUX_CFG, - DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL, - dp83869->io_impedance & - DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL); + ret = phy_modify_mmd(phydev, DP83869_DEVADDR, + DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL, + dp83869->io_impedance & + DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL); - return 0; + return ret; } static int dp83869_configure_mode(struct phy_device *phydev, @@ -284,9 +284,11 @@ static int dp83869_configure_mode(struct phy_device *phydev, return ret; break; case DP83869_RGMII_SGMII_BRIDGE: - phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, - DP83869_SGMII_RGMII_BRIDGE, - DP83869_SGMII_RGMII_BRIDGE); + ret = phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, + DP83869_SGMII_RGMII_BRIDGE, + DP83869_SGMII_RGMII_BRIDGE); + if (ret) + return ret; ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); @@ -334,7 +336,7 @@ static int dp83869_configure_mode(struct phy_device *phydev, return -EINVAL; }; - return 0; + return ret; } static int dp83869_config_init(struct phy_device *phydev) @@ -358,12 +360,13 @@ static int dp83869_config_init(struct phy_device *phydev) /* Clock output selection if muxing property is set */ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) - phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG, - DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, - dp83869->clk_output_sel << - DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); - return 0; + return ret; } static int dp83869_probe(struct phy_device *phydev) -- cgit v1.2.3-59-g8ed1b From a95069ecb7092d03b2ea1c39ee04514fe9627540 Mon Sep 17 00:00:00 2001 From: Jeroen de Borst Date: Tue, 26 Nov 2019 15:36:19 -0800 Subject: gve: Fix the queue page list allocated pages count In gve_alloc_queue_page_list(), when a page allocation fails, qpl->num_entries will be wrong. In this case priv->num_registered_pages can underflow in gve_free_queue_page_list(), causing subsequent calls to gve_alloc_queue_page_list() to fail. Fixes: f5cedc84a30d ("gve: Add transmit and receive support") Signed-off-by: Jeroen de Borst Reviewed-by: Catherine Sullivan Signed-off-by: David S. Miller --- drivers/net/ethernet/google/gve/gve_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index aca95f64bde8..9b7a8db9860f 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -544,7 +544,7 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id, } qpl->id = id; - qpl->num_entries = pages; + qpl->num_entries = 0; qpl->pages = kvzalloc(pages * sizeof(*qpl->pages), GFP_KERNEL); /* caller handles clean up */ if (!qpl->pages) @@ -562,6 +562,7 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id, /* caller handles clean up */ if (err) return -ENOMEM; + qpl->num_entries++; } priv->num_registered_pages += pages; -- cgit v1.2.3-59-g8ed1b From fc62c0948986b7aa6b2871a450a4469e35c5f9bc Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 27 Nov 2019 15:27:56 +0800 Subject: net: mscc: ocelot: avoid incorrect consuming in skbs list Break the matching loop when find the matching skb for TX timestamp. This is to avoid consuming more skbs incorrectly. The timestamp ID is from 0 to 3 while the FIFO could support 128 timestamps at most. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 0e96ffab3b05..6dc9de3454ba 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -736,6 +736,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) list_del(pos); kfree(entry); + break; } /* Next ts */ -- cgit v1.2.3-59-g8ed1b From b049da1338082714262034a8c8b87022623dc106 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 27 Nov 2019 15:27:57 +0800 Subject: net: mscc: ocelot: use skb queue instead of skbs list Convert to use skb queue instead of the list of skbs. The skb queue could provide protection with lock. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 54 +++++++++++++------------------------- include/soc/mscc/ocelot.h | 9 +------ 2 files changed, 19 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 6dc9de3454ba..2cccadc204fd 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -583,18 +583,10 @@ int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port, if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP && ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { - struct ocelot_skb *oskb = - kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC); - - if (unlikely(!oskb)) - return -ENOMEM; - shinfo->tx_flags |= SKBTX_IN_PROGRESS; - - oskb->skb = skb; - oskb->id = ocelot_port->ts_id % 4; - - list_add_tail(&oskb->head, &ocelot_port->skbs); + /* Store timestamp ID in cb[0] of sk_buff */ + skb->cb[0] = ocelot_port->ts_id % 4; + skb_queue_tail(&ocelot_port->tx_skbs, skb); return 0; } return -ENODATA; @@ -704,12 +696,11 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) int budget = OCELOT_PTP_QUEUE_SZ; while (budget--) { + struct sk_buff *skb, *skb_tmp, *skb_match = NULL; struct skb_shared_hwtstamps shhwtstamps; - struct list_head *pos, *tmp; - struct sk_buff *skb = NULL; - struct ocelot_skb *entry; struct ocelot_port *port; struct timespec64 ts; + unsigned long flags; u32 val, id, txport; val = ocelot_read(ocelot, SYS_PTP_STATUS); @@ -727,22 +718,22 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) /* Retrieve its associated skb */ port = ocelot->ports[txport]; - list_for_each_safe(pos, tmp, &port->skbs) { - entry = list_entry(pos, struct ocelot_skb, head); - if (entry->id != id) - continue; + spin_lock_irqsave(&port->tx_skbs.lock, flags); - skb = entry->skb; - - list_del(pos); - kfree(entry); + skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) { + if (skb->cb[0] != id) + continue; + __skb_unlink(skb, &port->tx_skbs); + skb_match = skb; break; } + spin_unlock_irqrestore(&port->tx_skbs.lock, flags); + /* Next ts */ ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT); - if (unlikely(!skb)) + if (unlikely(!skb_match)) continue; /* Get the h/w timestamp */ @@ -751,9 +742,9 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) /* Set the timestamp into the skb */ memset(&shhwtstamps, 0, sizeof(shhwtstamps)); shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); - skb_tstamp_tx(skb, &shhwtstamps); + skb_tstamp_tx(skb_match, &shhwtstamps); - dev_kfree_skb_any(skb); + dev_kfree_skb_any(skb_match); } } EXPORT_SYMBOL(ocelot_get_txtstamp); @@ -2206,7 +2197,7 @@ void ocelot_init_port(struct ocelot *ocelot, int port) { struct ocelot_port *ocelot_port = ocelot->ports[port]; - INIT_LIST_HEAD(&ocelot_port->skbs); + skb_queue_head_init(&ocelot_port->tx_skbs); /* Basic L2 initialization */ @@ -2491,9 +2482,7 @@ EXPORT_SYMBOL(ocelot_init); void ocelot_deinit(struct ocelot *ocelot) { - struct list_head *pos, *tmp; struct ocelot_port *port; - struct ocelot_skb *entry; int i; cancel_delayed_work(&ocelot->stats_work); @@ -2503,14 +2492,7 @@ void ocelot_deinit(struct ocelot *ocelot) for (i = 0; i < ocelot->num_phys_ports; i++) { port = ocelot->ports[i]; - - list_for_each_safe(pos, tmp, &port->skbs) { - entry = list_entry(pos, struct ocelot_skb, head); - - list_del(pos); - dev_kfree_skb_any(entry->skb); - kfree(entry); - } + skb_queue_purge(&port->tx_skbs); } } EXPORT_SYMBOL(ocelot_deinit); diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index e1108a5f4f17..64cbbbe74a36 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -406,13 +406,6 @@ struct ocelot_ops { int (*reset)(struct ocelot *ocelot); }; -struct ocelot_skb { - struct list_head head; - struct sk_buff *skb; - u8 id; -}; - - struct ocelot_port { struct ocelot *ocelot; @@ -425,7 +418,7 @@ struct ocelot_port { u16 vid; u8 ptp_cmd; - struct list_head skbs; + struct sk_buff_head tx_skbs; u8 ts_id; }; -- cgit v1.2.3-59-g8ed1b From b167191e2a851cb2e4c6ef8b91c83ff73ef41872 Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Wed, 27 Nov 2019 12:41:23 +0300 Subject: net: wireless: intel: iwlwifi: fix GRO_NORMAL packet stalling Commit 6570bc79c0df ("net: core: use listified Rx for GRO_NORMAL in napi_gro_receive()") has applied batched GRO_NORMAL packets processing to all napi_gro_receive() users, including mac80211-based drivers. However, this change has led to a regression in iwlwifi driver [1][2] as it is required for NAPI users to call napi_complete_done() or napi_complete() and the end of every polling iteration, whilst iwlwifi doesn't use NAPI scheduling at all and just calls napi_gro_flush(). In that particular case, packets which have not been already flushed from napi->rx_list stall in it until at least next Rx cycle. Fix this by adding a manual flushing of the list to iwlwifi driver right before napi_gro_flush() call to mimic napi_complete() logics. I prefer to open-code gro_normal_list() rather than exporting it for 2 reasons: * to prevent from using it and napi_gro_flush() in any new drivers, as it is the *really* bad way to use NAPI that should be avoided; * to keep gro_normal_list() static and don't lose any CC optimizations. I also don't add the "Fixes:" tag as the mentioned commit was only a trigger that only exposed an improper usage of NAPI in this particular driver. [1] https://lore.kernel.org/netdev/PSXP216MB04388962C411CD0B17A86F47804A0@PSXP216MB0438.KORP216.PROD.OUTLOOK.COM [2] https://bugzilla.kernel.org/show_bug.cgi?id=205647 Signed-off-by: Alexander Lobakin Acked-by: Luca Coelho Reported-by: Nicholas Johnson Tested-by: Nicholas Johnson Reviewed-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index a4d325fcf94a..452da44a21e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1421,6 +1421,7 @@ out_err: static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct napi_struct *napi; struct iwl_rxq *rxq; u32 r, i, count = 0; bool emergency = false; @@ -1526,8 +1527,16 @@ out: if (unlikely(emergency && count)) iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq); - if (rxq->napi.poll) - napi_gro_flush(&rxq->napi, false); + napi = &rxq->napi; + if (napi->poll) { + if (napi->rx_count) { + netif_receive_skb_list(&napi->rx_list); + INIT_LIST_HEAD(&napi->rx_list); + napi->rx_count = 0; + } + + napi_gro_flush(napi, false); + } iwl_pcie_rxq_restock(trans, rxq); } -- cgit v1.2.3-59-g8ed1b From 9aab906a9adc292f2bb7eccfd0b1c0aa862296ca Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Wed, 27 Nov 2019 18:49:08 +0530 Subject: net: phy: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header files related to PHY Layer for Ethernet drivers. For C header files Documentation/process/license-rules.rst mandates C-like comments (opposed to C source files where C++ style should be used). This patch also gives an explicit block comment to the SPDX License Identifier. Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46. Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Signed-off-by: David S. Miller --- drivers/net/phy/aquantia.h | 4 ++-- drivers/net/phy/bcm-phy-lib.h | 2 +- drivers/net/phy/mdio-cavium.h | 2 +- drivers/net/phy/mdio-i2c.h | 2 +- drivers/net/phy/mdio-xgene.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h index 5a16caab7b2f..c684b65c642c 100644 --- a/drivers/net/phy/aquantia.h +++ b/drivers/net/phy/aquantia.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * HWMON driver for Aquantia PHY +/* SPDX-License-Identifier: GPL-2.0 */ +/* HWMON driver for Aquantia PHY * * Author: Nikita Yushchenko * Author: Andrew Lunn diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 5ecacb4e64f0..c86fb9d1240c 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2015 Broadcom Corporation */ diff --git a/drivers/net/phy/mdio-cavium.h b/drivers/net/phy/mdio-cavium.h index b7f89ad27465..e33d3ea9a907 100644 --- a/drivers/net/phy/mdio-cavium.h +++ b/drivers/net/phy/mdio-cavium.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2009-2016 Cavium, Inc. */ diff --git a/drivers/net/phy/mdio-i2c.h b/drivers/net/phy/mdio-i2c.h index 751dab281f57..b1d27f7cd23f 100644 --- a/drivers/net/phy/mdio-i2c.h +++ b/drivers/net/phy/mdio-i2c.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MDIO I2C bridge * diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h index b1f5ccb4ad9c..8af93ada8b64 100644 --- a/drivers/net/phy/mdio-xgene.h +++ b/drivers/net/phy/mdio-xgene.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* Applied Micro X-Gene SoC MDIO Driver * * Copyright (c) 2016, Applied Micro Circuits Corporation -- cgit v1.2.3-59-g8ed1b From bac139a846697b290c74fefd6af54a9e192de315 Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Wed, 27 Nov 2019 19:15:52 +0530 Subject: net: usb: aqc111: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header files related to drivers for USB Network devices. This patch gives an explicit block comment to the SPDX License Identifier. Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46. Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Signed-off-by: David S. Miller --- drivers/net/usb/aqc111.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h index 4d68b3a6067c..b562db4da337 100644 --- a/drivers/net/usb/aqc111.h +++ b/drivers/net/usb/aqc111.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Aquantia Corp. Aquantia AQtion USB to 5GbE Controller +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller * Copyright (C) 2003-2005 David Hollis * Copyright (C) 2005 Phil Chang * Copyright (C) 2002-2003 TiVo Inc. -- cgit v1.2.3-59-g8ed1b