mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'net-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Paolo Abeni:
"This is again larger than usual: the backlog accumulated in the past weeks
is not done yet. I'm not aware of any known pending regression.
Including fixes from netfilter, Bluetooth, WiFi and CAN.
Current release - regressions:
- bluetooth: remove unnecessary hci_conn_get in create_conn_sync
- can: isotp: fix timer drain order, wakeup handling and tx_gen
ordering
- eth:
- tun/vhost: revert avoid ptr_ring tail-drop when a qdisc is
present
Previous releases - regressions:
- core: do not send ICMP/NDISC Redirects when peer allocation fails
- ipv6: take nexthop lock for f6i_list walks in replace check and
notify
- wifi: fix an ath12k MLO regression impacting WCN7850/QCC2072.
- netfilter: nf_tables: make nft_object rhltable per table
- af_unix: fix listen() succeeding on sockets in the wrong state
- openvswitch: fix potential UAF on meter attach failure
- bluetooth:
- fix advertising data UAFs
- avoid deadlocks in iso_sock_timeout
- smc: fix socket use-after-free during link group termination
- dpll: use pin owner's dpll ref for pin-level attribute reporting
- eth:
- veth: convert frag_list skbs before running XDP
- ice: wait for reset completion in ice_resume()
- igc: remove napi_synchronize() in igc_down()
- vxlan: use pskb_network_may_pull() for transmit path header pulls
Previous releases - always broken:
- xsk: fix AF_XDP multi-buffer Tx descriptor reclaim
- psp: fix NULL genl_sock deref race with concurrent netns teardown
- netfilter: widen NAT rewrite delta to s32 in sip_help_tcp()
- can: peak_usb: fix double free of transfer buffer on URB submit error
- dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister
- sctp: prevent peer transport count overflow
- dsa: mt7530: error out on failed reads in MT7531 PHY polling
- eth:
- idpf: bound interrupt-vector register fill to the allocated array"
* tag 'net-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (156 commits)
qede: sync udp_tunnel ports outside qede_lock in the recovery path
net: openvswitch: fix potential UAF on meter attach failure
octeontx2-pf: Set correct sequence for carrier off and tx queue stop
net: libwx: fix FDIR ATR queue mismatch for software VLAN packets
net: dsa: realtek: use devm_mutex_init for l2_lock
net: dsa: realtek: use devm_mutex_init for vlan_lock
net: dsa: realtek: use devm_mutex_init for regmap lock
net: dsa: realtek: rtl8365mb: use devm_mutex_init for mib_lock
ptp: netc: fix potential interrupt storm caused by incorrect unbind order
net: mana: Return error code from mana_create_rxq()
net: openvswitch: fix skb leak on flow key update failure during ct
net: openvswitch: fix skb leak on flow key update failure during recirculation
net: stmmac: Fix E2E delay mechanism
net: dsa: mt7530: error out on failed reads in MT7531 PHY polling
net: dsa: mt7530: error out on failed reads in ATC/VTCR command polling
net: dsa: mt7530: check bus->read() errors in the MDIO regmap backend
Revert "tun/tap: add ptr_ring consume helper with netdev queue wakeup"
Revert "vhost-net: wake queue of tun/tap after ptr_ring consume"
Revert "ptr_ring: move free-space check into separate helper"
Revert "tun/tap & vhost-net: avoid ptr_ring tail-drop when a qdisc is present"
...
This commit is contained in:
@@ -72,6 +72,7 @@ Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@nvidia.com>
|
||||
Alice Mikityanska <alice.kernel@fastmail.im> <maxim@isovalent.com>
|
||||
Alice Mikityanska <alice.kernel@fastmail.im> <alice@isovalent.com>
|
||||
Aloka Dixit <quic_alokad@quicinc.com> <alokad@codeaurora.org>
|
||||
Alvin Šipraga <alvin.sipraga@analog.com> <alsi@bang-olufsen.dk>
|
||||
Al Viro <viro@ftp.linux.org.uk>
|
||||
Al Viro <viro@zenIV.linux.org.uk>
|
||||
Amit Blay <quic_ablay@quicinc.com> <ablay@codeaurora.org>
|
||||
|
||||
@@ -43,12 +43,13 @@ UMEM also has two rings: the FILL ring and the COMPLETION ring. The
|
||||
FILL ring is used by the application to send down addr for the kernel
|
||||
to fill in with RX packet data. References to these frames will then
|
||||
appear in the RX ring once each packet has been received. The
|
||||
COMPLETION ring, on the other hand, contains frame addr that the
|
||||
kernel has transmitted completely and can now be used again by user
|
||||
space, for either TX or RX. Thus, the frame addrs appearing in the
|
||||
COMPLETION ring are addrs that were previously transmitted using the
|
||||
TX ring. In summary, the RX and FILL rings are used for the RX path
|
||||
and the TX and COMPLETION rings are used for the TX path.
|
||||
COMPLETION ring, on the other hand, contains frame addresses from Tx
|
||||
descriptors that the kernel has finished processing and that can now be
|
||||
used again by user space, for either Tx or Rx. This includes frames whose
|
||||
transmission has completed as well as frames referenced by invalid Tx
|
||||
descriptors rejected by the kernel. A completion therefore returns
|
||||
ownership of a frame to user space, but does not by itself guarantee that
|
||||
the packet was successfully transmitted.
|
||||
|
||||
The socket is then finally bound with a bind() call to a device and a
|
||||
specific queue id on that device, and it is not until bind is
|
||||
@@ -169,14 +170,15 @@ chunks mode, then the incoming addr will be left untouched.
|
||||
UMEM Completion Ring
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The COMPLETION Ring is used transfer ownership of UMEM frames from
|
||||
The COMPLETION Ring is used to transfer ownership of UMEM frames from
|
||||
kernel-space to user-space. Just like the FILL ring, UMEM indices are
|
||||
used.
|
||||
|
||||
Frames passed from the kernel to user-space are frames that has been
|
||||
sent (TX ring) and can be used by user-space again.
|
||||
|
||||
The user application consumes UMEM addrs from this ring.
|
||||
used. Frames passed from the kernel to user-space are frames referenced
|
||||
by Tx descriptors that the kernel has finished processing and can be
|
||||
used by user-space again. This includes both frames whose transmission
|
||||
has completed and frames referenced by invalid Tx descriptors that were
|
||||
rejected and reclaimed by the kernel. A completion entry does not
|
||||
guarantee successful packet transmission. The user application consumes
|
||||
UMEM addrs from this ring.
|
||||
|
||||
|
||||
RX Ring
|
||||
@@ -504,21 +506,25 @@ will be treated as an invalid descriptor.
|
||||
These are the semantics for producing packets onto AF_XDP Tx ring
|
||||
consisting of multiple frames:
|
||||
|
||||
* When an invalid descriptor is found, all the other
|
||||
descriptors/frames of this packet are marked as invalid and not
|
||||
completed. The next descriptor is treated as the start of a new
|
||||
packet, even if this was not the intent (because we cannot guess
|
||||
the intent). As before, if your program is producing invalid
|
||||
descriptors you have a bug that must be fixed.
|
||||
* When an invalid descriptor is found, the complete packet is treated as
|
||||
invalid. The kernel consumes descriptors through the descriptor marking
|
||||
the end of the packet and returns all their frame addresses through the
|
||||
COMPLETION ring. A standalone invalid descriptor is treated as a
|
||||
one-descriptor invalid packet. The descriptor following the end of the
|
||||
invalid packet is treated as the start of a new packet. As before, if
|
||||
your program is producing invalid descriptors you have a bug that must
|
||||
be fixed. Rejected descriptors are reported in the ``tx_invalid_descs``
|
||||
statistic.
|
||||
|
||||
* Zero length descriptors are treated as invalid descriptors.
|
||||
|
||||
* For copy mode, the maximum supported number of frames in a packet is
|
||||
equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all
|
||||
descriptors accumulated so far are dropped and treated as
|
||||
invalid. To produce an application that will work on any system
|
||||
regardless of this config setting, limit the number of frags to 18,
|
||||
as the minimum value of the config is 17.
|
||||
equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all descriptors
|
||||
through the end of the oversized packet are consumed, treated as invalid,
|
||||
and their frame addresses are returned through the COMPLETION ring. To
|
||||
produce an application that will work on any system regardless of this
|
||||
config setting, limit the number of frags to 18, as the minimum value of
|
||||
the config is 17.
|
||||
|
||||
* For zero-copy mode, the limit is up to what the NIC HW
|
||||
supports. Usually at least five on the NICs we have checked. We
|
||||
|
||||
+3
-3
@@ -22736,7 +22736,8 @@ F: drivers/watchdog/realtek_otto_wdt.c
|
||||
|
||||
REALTEK RTL83xx SMI DSA ROUTER CHIPS
|
||||
M: Linus Walleij <linusw@kernel.org>
|
||||
M: Alvin Šipraga <alsi@bang-olufsen.dk>
|
||||
M: Luiz Angelo Daros de Luca <luizluca@gmail.com>
|
||||
R: Alvin Šipraga <alvin.sipraga@analog.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/dsa/realtek.yaml
|
||||
F: drivers/net/dsa/realtek/*
|
||||
@@ -24633,8 +24634,7 @@ SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
|
||||
M: D. Wythe <alibuda@linux.alibaba.com>
|
||||
M: Dust Li <dust.li@linux.alibaba.com>
|
||||
M: Sidraya Jayagond <sidraya@linux.ibm.com>
|
||||
M: Wenjia Zhang <wenjia@linux.ibm.com>
|
||||
R: Mahanta Jambigi <mjambigi@linux.ibm.com>
|
||||
M: Mahanta Jambigi <mjambigi@linux.ibm.com>
|
||||
R: Tony Lu <tonylu@linux.alibaba.com>
|
||||
R: Wen Gu <guwen@linux.alibaba.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
|
||||
@@ -3771,6 +3771,9 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct intel_tlv *tlv = (void *)&skb->data[5];
|
||||
|
||||
if (skb->len < 5 + sizeof(*tlv) + sizeof(tlv->val[0]))
|
||||
goto recv_frame;
|
||||
|
||||
/* The first event is always an event type TLV */
|
||||
if (tlv->type != INTEL_TLV_TYPE_ID)
|
||||
goto recv_frame;
|
||||
|
||||
+37
-49
@@ -804,56 +804,44 @@ static int btmtk_usb_uhw_reg_write(struct hci_dev *hdev, u32 reg, u32 val)
|
||||
static int btmtk_usb_uhw_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
{
|
||||
struct btmtk_data *data = hci_get_priv(hdev);
|
||||
int pipe, err;
|
||||
void *buf;
|
||||
u8 buf[sizeof(u32)];
|
||||
int err;
|
||||
|
||||
buf = kzalloc(4, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pipe = usb_rcvctrlpipe(data->udev, 0);
|
||||
err = usb_control_msg(data->udev, pipe, 0x01,
|
||||
0xDE,
|
||||
reg >> 16, reg & 0xffff,
|
||||
buf, 4, USB_CTRL_GET_TIMEOUT);
|
||||
if (err < 0) {
|
||||
*val = 0;
|
||||
err = usb_control_msg_recv(data->udev, 0, 0x01,
|
||||
0xDE,
|
||||
reg >> 16, reg & 0xffff,
|
||||
buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
|
||||
GFP_KERNEL);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Failed to read uhw reg(%d)", err);
|
||||
goto err_free_buf;
|
||||
return err;
|
||||
}
|
||||
|
||||
*val = get_unaligned_le32(buf);
|
||||
bt_dev_dbg(hdev, "reg=%x, value=0x%08x", reg, *val);
|
||||
|
||||
err_free_buf:
|
||||
kfree(buf);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btmtk_usb_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
{
|
||||
struct btmtk_data *data = hci_get_priv(hdev);
|
||||
int pipe, err, size = sizeof(u32);
|
||||
void *buf;
|
||||
u8 buf[sizeof(u32)];
|
||||
int err;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pipe = usb_rcvctrlpipe(data->udev, 0);
|
||||
err = usb_control_msg(data->udev, pipe, 0x63,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
reg >> 16, reg & 0xffff,
|
||||
buf, size, USB_CTRL_GET_TIMEOUT);
|
||||
*val = 0;
|
||||
err = usb_control_msg_recv(data->udev, 0, 0x63,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
reg >> 16, reg & 0xffff,
|
||||
buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
|
||||
GFP_KERNEL);
|
||||
if (err < 0)
|
||||
goto err_free_buf;
|
||||
return err;
|
||||
|
||||
*val = get_unaligned_le32(buf);
|
||||
|
||||
err_free_buf:
|
||||
kfree(buf);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btmtk_usb_id_get(struct hci_dev *hdev, u32 reg, u32 *id)
|
||||
@@ -877,7 +865,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
|
||||
if (dev_id == 0x7922) {
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
val |= 0x00002020;
|
||||
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
|
||||
@@ -887,7 +875,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
val |= BIT(0);
|
||||
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
|
||||
@@ -896,14 +884,14 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
msleep(100);
|
||||
} else if (dev_id == 0x7925 || dev_id == 0x6639) {
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
val |= (1 << 5);
|
||||
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
val &= 0xFFFF00FF;
|
||||
val |= (1 << 13);
|
||||
@@ -914,7 +902,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
val |= (1 << 0);
|
||||
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
|
||||
@@ -924,13 +912,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
msleep(100);
|
||||
} else {
|
||||
@@ -940,7 +928,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_WDT_STATUS, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
/* Reset the bluetooth chip via USB interface. */
|
||||
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, 1);
|
||||
@@ -950,13 +938,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
/* MT7921 need to delay 20ms between toggle reset bit */
|
||||
msleep(20);
|
||||
@@ -964,7 +952,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -980,7 +968,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
|
||||
}
|
||||
|
||||
err = btmtk_usb_id_get(hdev, 0x70010200, &val);
|
||||
if (err < 0 || (!val && dev_id != 0x6639))
|
||||
if (err || (!val && dev_id != 0x6639))
|
||||
bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
|
||||
|
||||
return err;
|
||||
@@ -1324,24 +1312,24 @@ int btmtk_usb_setup(struct hci_dev *hdev)
|
||||
calltime = ktime_get();
|
||||
|
||||
err = btmtk_usb_id_get(hdev, 0x80000008, &dev_id);
|
||||
if (err < 0) {
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Failed to get device id (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!dev_id || dev_id != 0x7663) {
|
||||
err = btmtk_usb_id_get(hdev, 0x70010200, &dev_id);
|
||||
if (err < 0) {
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Failed to get device id (%d)", err);
|
||||
return err;
|
||||
}
|
||||
err = btmtk_usb_id_get(hdev, 0x80021004, &fw_version);
|
||||
if (err < 0) {
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
|
||||
return err;
|
||||
}
|
||||
err = btmtk_usb_id_get(hdev, 0x70010020, &fw_flavor);
|
||||
if (err < 0) {
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Failed to get fw flavor (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -3424,28 +3424,16 @@ static const char *qca_get_fw_subdirectory(const struct qca_version *ver)
|
||||
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
|
||||
void *data, u16 size)
|
||||
{
|
||||
int pipe, err;
|
||||
u8 *buf;
|
||||
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
int err;
|
||||
|
||||
/* Found some of USB hosts have IOT issues with ours so that we should
|
||||
* not wait until HCI layer is ready.
|
||||
*/
|
||||
pipe = usb_rcvctrlpipe(udev, 0);
|
||||
err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
0, 0, buf, size, USB_CTRL_GET_TIMEOUT);
|
||||
if (err < 0) {
|
||||
err = usb_control_msg_recv(udev, 0, request, USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
0, 0, data, size, USB_CTRL_GET_TIMEOUT,
|
||||
GFP_KERNEL);
|
||||
if (err)
|
||||
dev_err(&udev->dev, "Failed to access otp area (%d)", err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(data, buf, size);
|
||||
|
||||
done:
|
||||
kfree(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -3652,7 +3640,7 @@ static bool btusb_qca_need_patch(struct usb_device *udev)
|
||||
struct qca_version ver;
|
||||
|
||||
if (btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
|
||||
sizeof(ver)) < 0)
|
||||
sizeof(ver)))
|
||||
return false;
|
||||
/* only low ROM versions need patches */
|
||||
return !(le32_to_cpu(ver.rom_version) & ~0xffffU);
|
||||
@@ -3670,7 +3658,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
||||
|
||||
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
|
||||
sizeof(ver));
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ver_rom = le32_to_cpu(ver.rom_version);
|
||||
@@ -3693,7 +3681,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
||||
|
||||
err = btusb_qca_send_vendor_req(udev, QCA_CHECK_STATUS, &status,
|
||||
sizeof(status));
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!(status & QCA_PATCH_UPDATED)) {
|
||||
@@ -3704,7 +3692,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
||||
|
||||
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
|
||||
sizeof(ver));
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
|
||||
|
||||
@@ -118,14 +118,9 @@ err_bit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
|
||||
struct dibs_lo_dmb_node *dmb_node)
|
||||
static void dibs_lo_free_dmb(struct dibs_lo_dev *ldev,
|
||||
struct dibs_lo_dmb_node *dmb_node)
|
||||
{
|
||||
/* remove dmb from hash table */
|
||||
write_lock_bh(&ldev->dmb_ht_lock);
|
||||
hash_del(&dmb_node->list);
|
||||
write_unlock_bh(&ldev->dmb_ht_lock);
|
||||
|
||||
clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
|
||||
folio_put(virt_to_folio(dmb_node->cpu_addr));
|
||||
kfree(dmb_node);
|
||||
@@ -139,27 +134,33 @@ static int dibs_lo_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
|
||||
struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
|
||||
struct dibs_lo_dev *ldev;
|
||||
unsigned long flags;
|
||||
bool last;
|
||||
|
||||
ldev = dibs->drv_priv;
|
||||
|
||||
/* find dmb from hash table */
|
||||
read_lock_bh(&ldev->dmb_ht_lock);
|
||||
write_lock_bh(&ldev->dmb_ht_lock);
|
||||
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
|
||||
if (tmp_node->token == dmb->dmb_tok) {
|
||||
dmb_node = tmp_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&ldev->dmb_ht_lock);
|
||||
if (!dmb_node)
|
||||
if (!dmb_node) {
|
||||
write_unlock_bh(&ldev->dmb_ht_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
last = refcount_dec_and_test(&dmb_node->refcnt);
|
||||
if (last)
|
||||
hash_del(&dmb_node->list);
|
||||
write_unlock_bh(&ldev->dmb_ht_lock);
|
||||
|
||||
if (refcount_dec_and_test(&dmb_node->refcnt)) {
|
||||
if (last) {
|
||||
spin_lock_irqsave(&dibs->lock, flags);
|
||||
dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
|
||||
spin_unlock_irqrestore(&dibs->lock, flags);
|
||||
|
||||
__dibs_lo_unregister_dmb(ldev, dmb_node);
|
||||
dibs_lo_free_dmb(ldev, dmb_node);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -188,14 +189,9 @@ static int dibs_lo_attach_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
|
||||
read_unlock_bh(&ldev->dmb_ht_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
refcount_inc(&dmb_node->refcnt);
|
||||
read_unlock_bh(&ldev->dmb_ht_lock);
|
||||
|
||||
if (!refcount_inc_not_zero(&dmb_node->refcnt))
|
||||
/* the dmb is being unregistered, but has
|
||||
* not been removed from the hash table.
|
||||
*/
|
||||
return -EINVAL;
|
||||
|
||||
/* provide dmb information */
|
||||
dmb->idx = dmb_node->sba_idx;
|
||||
dmb->dmb_tok = dmb_node->token;
|
||||
@@ -209,11 +205,12 @@ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
|
||||
{
|
||||
struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
|
||||
struct dibs_lo_dev *ldev;
|
||||
bool last;
|
||||
|
||||
ldev = dibs->drv_priv;
|
||||
|
||||
/* find dmb_node according to dmb->dmb_tok */
|
||||
read_lock_bh(&ldev->dmb_ht_lock);
|
||||
write_lock_bh(&ldev->dmb_ht_lock);
|
||||
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
|
||||
if (tmp_node->token == token) {
|
||||
dmb_node = tmp_node;
|
||||
@@ -221,13 +218,17 @@ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
|
||||
}
|
||||
}
|
||||
if (!dmb_node) {
|
||||
read_unlock_bh(&ldev->dmb_ht_lock);
|
||||
write_unlock_bh(&ldev->dmb_ht_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
read_unlock_bh(&ldev->dmb_ht_lock);
|
||||
last = refcount_dec_and_test(&dmb_node->refcnt);
|
||||
if (last)
|
||||
hash_del(&dmb_node->list);
|
||||
write_unlock_bh(&ldev->dmb_ht_lock);
|
||||
|
||||
if (last)
|
||||
dibs_lo_free_dmb(ldev, dmb_node);
|
||||
|
||||
if (refcount_dec_and_test(&dmb_node->refcnt))
|
||||
__dibs_lo_unregister_dmb(ldev, dmb_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1142,6 +1142,33 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
|
||||
return reg->priv;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpll_pin_own_dpll_ref_first - find the first owner dpll ref of a pin
|
||||
* @pin: pointer to a dpll pin
|
||||
*
|
||||
* Search pin's dpll_refs for a ref whose dpll matches the pin's
|
||||
* (module, clock_id) tuple, i.e. the dpll registered by the driver
|
||||
* that created the pin. This ensures pin-level attributes are
|
||||
* reported and modified using the owner's ops even when the pin is
|
||||
* also registered with dplls from other drivers.
|
||||
*
|
||||
* Return: pointer to the owner's dpll_pin_ref, or NULL if no
|
||||
* owner ref is found.
|
||||
*/
|
||||
struct dpll_pin_ref *dpll_pin_own_dpll_ref_first(struct dpll_pin *pin)
|
||||
{
|
||||
struct dpll_pin_ref *ref;
|
||||
unsigned long i;
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
if (ref->dpll->module == pin->module &&
|
||||
ref->dpll->clock_id == pin->clock_id)
|
||||
return ref;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
|
||||
@@ -93,6 +93,7 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent, struct dpll_pin *pin);
|
||||
|
||||
const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll);
|
||||
struct dpll_device *dpll_device_get_by_id(int id);
|
||||
struct dpll_pin_ref *dpll_pin_own_dpll_ref_first(struct dpll_pin *pin);
|
||||
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref);
|
||||
struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs);
|
||||
extern struct xarray dpll_device_xa;
|
||||
|
||||
+50
-10
@@ -699,7 +699,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
|
||||
struct dpll_pin_ref *ref;
|
||||
int ret;
|
||||
|
||||
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref)
|
||||
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||
ASSERT_NOT_NULL(ref);
|
||||
|
||||
ret = dpll_msg_add_pin_handle(msg, pin);
|
||||
@@ -1090,12 +1092,19 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->frequency_set || !ops->frequency_get) {
|
||||
NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
|
||||
if ((!ops->frequency_set || !ops->frequency_get) &&
|
||||
ref->dpll->module == pin->module &&
|
||||
ref->dpll->clock_id == pin->clock_id) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"frequency set not supported by the device");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
ops = dpll_pin_ops(ref);
|
||||
dpll = ref->dpll;
|
||||
ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
|
||||
@@ -1109,6 +1118,8 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->frequency_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), freq, extack);
|
||||
@@ -1128,6 +1139,8 @@ rollback:
|
||||
if (ref == failed)
|
||||
break;
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->frequency_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), old_freq, extack))
|
||||
@@ -1151,13 +1164,19 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->esync_set || !ops->esync_get) {
|
||||
if ((!ops->esync_set || !ops->esync_get) &&
|
||||
ref->dpll->module == pin->module &&
|
||||
ref->dpll->clock_id == pin->clock_id) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"embedded sync feature is not supported by this device");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
ops = dpll_pin_ops(ref);
|
||||
dpll = ref->dpll;
|
||||
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
|
||||
@@ -1181,6 +1200,8 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
|
||||
void *pin_dpll_priv;
|
||||
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->esync_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
|
||||
ret = ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
|
||||
@@ -1204,6 +1225,8 @@ rollback:
|
||||
if (ref == failed)
|
||||
break;
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->esync_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
|
||||
if (ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
|
||||
@@ -1238,8 +1261,11 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
||||
NL_SET_ERR_MSG(extack, "reference sync pin not available");
|
||||
return -EINVAL;
|
||||
}
|
||||
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||
ASSERT_NOT_NULL(ref);
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->ref_sync_set || !ops->ref_sync_get) {
|
||||
NL_SET_ERR_MSG(extack, "reference sync not supported by this pin");
|
||||
@@ -1258,6 +1284,8 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
||||
return 0;
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->ref_sync_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
@@ -1280,6 +1308,8 @@ rollback:
|
||||
if (ref == failed)
|
||||
break;
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->ref_sync_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
if (ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
@@ -1471,12 +1501,18 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
|
||||
if ((!ops->phase_adjust_set || !ops->phase_adjust_get) &&
|
||||
ref->dpll->module == pin->module &&
|
||||
ref->dpll->clock_id == pin->clock_id) {
|
||||
NL_SET_ERR_MSG(extack, "phase adjust not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
ops = dpll_pin_ops(ref);
|
||||
dpll = ref->dpll;
|
||||
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
@@ -1491,6 +1527,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->phase_adjust_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
ret = ops->phase_adjust_set(pin,
|
||||
dpll_pin_on_dpll_priv(dpll, pin),
|
||||
@@ -1513,6 +1551,8 @@ rollback:
|
||||
if (ref == failed)
|
||||
break;
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->phase_adjust_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), old_phase_adj,
|
||||
|
||||
@@ -597,20 +597,20 @@ static int c_can_chip_config(struct net_device *dev)
|
||||
return err;
|
||||
|
||||
/* enable automatic retransmission */
|
||||
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR);
|
||||
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR | CONTROL_INIT);
|
||||
|
||||
if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
|
||||
(priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
|
||||
/* loopback + silent mode : useful for hot self-test */
|
||||
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
|
||||
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
|
||||
priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK | TEST_SILENT);
|
||||
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
|
||||
/* loopback mode : useful for self-test function */
|
||||
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
|
||||
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
|
||||
priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
|
||||
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
|
||||
/* silent mode : bus-monitoring mode */
|
||||
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
|
||||
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
|
||||
priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
|
||||
}
|
||||
|
||||
|
||||
@@ -340,8 +340,8 @@ static void ctucan_set_mode(struct ctucan_priv *priv, const struct can_ctrlmode
|
||||
(mode_reg & ~REG_MODE_FDE);
|
||||
|
||||
mode_reg = (mode->flags & CAN_CTRLMODE_PRESUME_ACK) ?
|
||||
(mode_reg | REG_MODE_ACF) :
|
||||
(mode_reg & ~REG_MODE_ACF);
|
||||
(mode_reg | REG_MODE_STM) :
|
||||
(mode_reg & ~REG_MODE_STM);
|
||||
|
||||
mode_reg = (mode->flags & CAN_CTRLMODE_FD_NON_ISO) ?
|
||||
(mode_reg | REG_MODE_NISOFD) :
|
||||
@@ -869,7 +869,7 @@ static void ctucan_err_interrupt(struct net_device *ndev, u32 isr)
|
||||
break;
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_CNT;
|
||||
cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
|
||||
cf->data[1] = CAN_ERR_CRTL_ACTIVE;
|
||||
cf->data[6] = bec.txerr;
|
||||
cf->data[7] = bec.rxerr;
|
||||
@@ -1136,8 +1136,12 @@ static irqreturn_t ctucan_interrupt(int irq, void *dev_id)
|
||||
/* Error interrupts */
|
||||
if (FIELD_GET(REG_INT_STAT_EWLI, isr) ||
|
||||
FIELD_GET(REG_INT_STAT_FCSI, isr) ||
|
||||
FIELD_GET(REG_INT_STAT_ALI, isr)) {
|
||||
icr = isr & (REG_INT_STAT_EWLI | REG_INT_STAT_FCSI | REG_INT_STAT_ALI);
|
||||
FIELD_GET(REG_INT_STAT_ALI, isr) ||
|
||||
FIELD_GET(REG_INT_STAT_BEI, isr)) {
|
||||
icr = isr & (REG_INT_STAT_EWLI |
|
||||
REG_INT_STAT_FCSI |
|
||||
REG_INT_STAT_ALI |
|
||||
REG_INT_STAT_BEI);
|
||||
|
||||
ctucan_netdev_dbg(ndev, "some ERR interrupt: clearing 0x%08x\n", icr);
|
||||
ctucan_write32(priv, CTUCANFD_INT_STAT, icr);
|
||||
|
||||
@@ -194,7 +194,7 @@ err_free_board:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(bdata);
|
||||
err_pci_iounmap_bar0:
|
||||
pci_iounmap(pdev, cra_addr);
|
||||
pci_iounmap(pdev, bar0_base);
|
||||
err_pci_iounmap_bar1:
|
||||
pci_iounmap(pdev, addr);
|
||||
err_release_regions:
|
||||
@@ -266,6 +266,7 @@ static const struct pci_device_id ctucan_pci_tbl[] = {
|
||||
CTUCAN_WITH_CTUCAN_ID)},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ctucan_pci_tbl);
|
||||
|
||||
static struct pci_driver ctucan_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
|
||||
@@ -2003,20 +2003,12 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
|
||||
u32 ch, sts;
|
||||
int err;
|
||||
|
||||
err = reset_control_reset(gpriv->rstc1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = reset_control_reset(gpriv->rstc2);
|
||||
if (err)
|
||||
goto fail_reset1;
|
||||
|
||||
/* Enable peripheral clock for register access */
|
||||
err = clk_prepare_enable(gpriv->clkp);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable peripheral clock: %pe\n",
|
||||
ERR_PTR(err));
|
||||
goto fail_reset2;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Enable RAM clock */
|
||||
@@ -2027,10 +2019,18 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
|
||||
goto fail_clk;
|
||||
}
|
||||
|
||||
err = reset_control_reset(gpriv->rstc1);
|
||||
if (err)
|
||||
goto fail_ram_clk;
|
||||
|
||||
err = reset_control_reset(gpriv->rstc2);
|
||||
if (err)
|
||||
goto fail_reset1;
|
||||
|
||||
err = rcar_canfd_reset_controller(gpriv);
|
||||
if (err) {
|
||||
dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));
|
||||
goto fail_ram_clk;
|
||||
goto fail_reset2;
|
||||
}
|
||||
|
||||
/* Controller in Global reset & Channel reset mode */
|
||||
@@ -2068,14 +2068,14 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
|
||||
|
||||
fail_mode:
|
||||
rcar_canfd_disable_global_interrupts(gpriv);
|
||||
fail_ram_clk:
|
||||
clk_disable_unprepare(gpriv->clk_ram);
|
||||
fail_clk:
|
||||
clk_disable_unprepare(gpriv->clkp);
|
||||
fail_reset2:
|
||||
reset_control_assert(gpriv->rstc2);
|
||||
fail_reset1:
|
||||
reset_control_assert(gpriv->rstc1);
|
||||
fail_ram_clk:
|
||||
clk_disable_unprepare(gpriv->clk_ram);
|
||||
fail_clk:
|
||||
clk_disable_unprepare(gpriv->clkp);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -2090,10 +2090,10 @@ static void rcar_canfd_global_deinit(struct rcar_canfd_global *gpriv, bool full)
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(gpriv->clk_ram);
|
||||
clk_disable_unprepare(gpriv->clkp);
|
||||
reset_control_assert(gpriv->rstc2);
|
||||
reset_control_assert(gpriv->rstc1);
|
||||
clk_disable_unprepare(gpriv->clk_ram);
|
||||
clk_disable_unprepare(gpriv->clkp);
|
||||
}
|
||||
|
||||
static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
|
||||
@@ -91,12 +91,12 @@ int softing_bootloader_command(struct softing *card, int16_t cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
|
||||
uint16_t *plen, const uint8_t **pdat)
|
||||
static int fw_parse(const u8 **pmem, const u8 *limit, u16 *ptype,
|
||||
u32 *paddr, u16 *plen, const u8 **pdat)
|
||||
{
|
||||
uint16_t checksum[2];
|
||||
const uint8_t *mem;
|
||||
const uint8_t *end;
|
||||
const u8 *mem;
|
||||
const u8 *record_end;
|
||||
|
||||
/*
|
||||
* firmware records are a binary, unaligned stream composed of:
|
||||
@@ -114,14 +114,21 @@ static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
|
||||
* endianness & alignment.
|
||||
*/
|
||||
mem = *pmem;
|
||||
/* A record needs an 8-byte prefix and a 2-byte checksum. */
|
||||
if (mem > limit || limit - mem < 10)
|
||||
return -EINVAL;
|
||||
|
||||
*ptype = le16_to_cpup((void *)&mem[0]);
|
||||
*paddr = le32_to_cpup((void *)&mem[2]);
|
||||
*plen = le16_to_cpup((void *)&mem[6]);
|
||||
if (*plen > limit - mem - 10)
|
||||
return -EINVAL;
|
||||
|
||||
*pdat = &mem[8];
|
||||
/* verify checksum */
|
||||
end = &mem[8 + *plen];
|
||||
checksum[0] = le16_to_cpup((void *)end);
|
||||
for (checksum[1] = 0; mem < end; ++mem)
|
||||
record_end = &mem[8 + *plen];
|
||||
checksum[0] = le16_to_cpup((void *)record_end);
|
||||
for (checksum[1] = 0; mem < record_end; ++mem)
|
||||
checksum[1] += *mem;
|
||||
if (checksum[0] != checksum[1])
|
||||
return -EINVAL;
|
||||
@@ -139,6 +146,7 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||
uint16_t type, len;
|
||||
uint32_t addr;
|
||||
uint8_t *buf = NULL, *new_buf;
|
||||
s64 dpram_offset;
|
||||
int buflen = 0;
|
||||
int8_t type_end = 0;
|
||||
|
||||
@@ -153,7 +161,7 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||
mem = fw->data;
|
||||
end = &mem[fw->size];
|
||||
/* look for header record */
|
||||
ret = fw_parse(&mem, &type, &addr, &len, &dat);
|
||||
ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
|
||||
if (ret < 0)
|
||||
goto failed;
|
||||
if (type != 0xffff)
|
||||
@@ -164,7 +172,7 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||
}
|
||||
/* ok, we had a header */
|
||||
while (mem < end) {
|
||||
ret = fw_parse(&mem, &type, &addr, &len, &dat);
|
||||
ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
|
||||
if (ret < 0)
|
||||
goto failed;
|
||||
if (type == 3) {
|
||||
@@ -179,9 +187,13 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if ((addr + len + offset) > size)
|
||||
dpram_offset = (s64)addr + offset;
|
||||
if (dpram_offset < 0 || dpram_offset > size ||
|
||||
len > size - dpram_offset) {
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
memcpy_toio(&dpram[addr + offset], dat, len);
|
||||
}
|
||||
memcpy_toio(&dpram[dpram_offset], dat, len);
|
||||
/* be sure to flush caches from IO space */
|
||||
mb();
|
||||
if (len > buflen) {
|
||||
@@ -195,7 +207,7 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||
buf = new_buf;
|
||||
}
|
||||
/* verify record data */
|
||||
memcpy_fromio(buf, &dpram[addr + offset], len);
|
||||
memcpy_fromio(buf, &dpram[dpram_offset], len);
|
||||
if (memcmp(buf, dat, len)) {
|
||||
/* is not ok */
|
||||
dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
|
||||
@@ -237,7 +249,7 @@ int softing_load_app_fw(const char *file, struct softing *card)
|
||||
mem = fw->data;
|
||||
end = &mem[fw->size];
|
||||
/* look for header record */
|
||||
ret = fw_parse(&mem, &type, &addr, &len, &dat);
|
||||
ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
|
||||
if (ret)
|
||||
goto failed;
|
||||
ret = -EINVAL;
|
||||
@@ -253,7 +265,7 @@ int softing_load_app_fw(const char *file, struct softing *card)
|
||||
}
|
||||
/* ok, we had a header */
|
||||
while (mem < end) {
|
||||
ret = fw_parse(&mem, &type, &addr, &len, &dat);
|
||||
ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
@@ -279,6 +291,12 @@ int softing_load_app_fw(const char *file, struct softing *card)
|
||||
/* work in 16bit (target) */
|
||||
sum &= 0xffff;
|
||||
|
||||
if (card->pdat->app.offs > card->dpram_size ||
|
||||
len > card->dpram_size - card->pdat->app.offs) {
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
|
||||
iowrite32(card->pdat->app.offs + card->pdat->app.addr,
|
||||
&card->dpram[DPRAM_COMMAND + 2]);
|
||||
|
||||
@@ -409,6 +409,40 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
|
||||
netif_rx(skb);
|
||||
}
|
||||
|
||||
static bool ems_usb_rx_msg_len_valid(struct ems_cpc_msg *msg)
|
||||
{
|
||||
size_t len = msg->length;
|
||||
size_t can_len;
|
||||
|
||||
switch (msg->type) {
|
||||
case CPC_MSG_TYPE_CAN_STATE:
|
||||
return len >= sizeof(msg->msg.can_state);
|
||||
|
||||
case CPC_MSG_TYPE_CAN_FRAME:
|
||||
case CPC_MSG_TYPE_EXT_CAN_FRAME:
|
||||
case CPC_MSG_TYPE_RTR_FRAME:
|
||||
case CPC_MSG_TYPE_EXT_RTR_FRAME:
|
||||
if (len < CPC_CAN_MSG_MIN_SIZE)
|
||||
return false;
|
||||
|
||||
if (msg->type == CPC_MSG_TYPE_RTR_FRAME ||
|
||||
msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME)
|
||||
return true;
|
||||
|
||||
can_len = can_cc_dlc2len(msg->msg.can_msg.length & 0xf);
|
||||
return len >= CPC_CAN_MSG_MIN_SIZE + can_len;
|
||||
|
||||
case CPC_MSG_TYPE_CAN_FRAME_ERROR:
|
||||
return len >= sizeof(msg->msg.error);
|
||||
|
||||
case CPC_MSG_TYPE_OVERRUN:
|
||||
return len >= sizeof(msg->msg.overrun);
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* callback for bulk IN urb
|
||||
*/
|
||||
@@ -451,6 +485,15 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
|
||||
}
|
||||
|
||||
msg = (struct ems_cpc_msg *)&ibuf[start];
|
||||
if (msg->length >
|
||||
urb->actual_length - start - CPC_MSG_HEADER_LEN) {
|
||||
netdev_err(netdev, "format error\n");
|
||||
break;
|
||||
}
|
||||
if (!ems_usb_rx_msg_len_valid(msg)) {
|
||||
netdev_err(netdev, "format error\n");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (msg->type) {
|
||||
case CPC_MSG_TYPE_CAN_STATE:
|
||||
|
||||
@@ -1476,7 +1476,6 @@ static void es58x_read_bulk_callback(struct urb *urb)
|
||||
dev_err_ratelimited(dev,
|
||||
"Failed resubmitting read bulk urb: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
return;
|
||||
|
||||
free_urb:
|
||||
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
|
||||
|
||||
@@ -674,7 +674,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
||||
if (hf->flags & GS_CAN_FLAG_FD) {
|
||||
skb = alloc_canfd_skb(netdev, &cfd);
|
||||
if (!skb)
|
||||
return;
|
||||
goto resubmit_urb;
|
||||
|
||||
cfd->can_id = le32_to_cpu(hf->can_id);
|
||||
cfd->len = data_length;
|
||||
@@ -687,7 +687,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
||||
} else {
|
||||
skb = alloc_can_skb(netdev, &cf);
|
||||
if (!skb)
|
||||
return;
|
||||
goto resubmit_urb;
|
||||
|
||||
cf->can_id = le32_to_cpu(hf->can_id);
|
||||
can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
|
||||
|
||||
@@ -1626,6 +1626,7 @@ static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv,
|
||||
reinit_completion(&priv->get_busparams_comp);
|
||||
|
||||
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
|
||||
kfree(cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -691,13 +691,22 @@ static int kvaser_usb_leaf_wait_cmd(const struct kvaser_usb *dev, u8 id,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pos + tmp->len > actual_len) {
|
||||
if (tmp->len < CMD_HEADER_LEN ||
|
||||
tmp->len > actual_len - pos) {
|
||||
dev_err_ratelimited(&dev->intf->dev,
|
||||
"Format error\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp->id == id) {
|
||||
if (tmp->len > sizeof(*cmd)) {
|
||||
dev_err_ratelimited(&dev->intf->dev,
|
||||
"Received command %u too large (%u)\n",
|
||||
tmp->id, tmp->len);
|
||||
err = -EIO;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memcpy(cmd, tmp, tmp->len);
|
||||
goto end;
|
||||
}
|
||||
@@ -1737,7 +1746,7 @@ static void kvaser_usb_leaf_read_bulk_callback(struct kvaser_usb *dev,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pos + cmd->len > len) {
|
||||
if (cmd->len < CMD_HEADER_LEN || cmd->len > len - pos) {
|
||||
dev_err_ratelimited(&dev->intf->dev, "Format error\n");
|
||||
break;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user