RK3568 CAN波特率500K接收数据导致CPU4满载
最近调试RK3568 CAN时发现,当CAN作为接收端,在快速接收数据时会导致cpu4满载。down掉can口或者断开外设时恢复正常。并且问题只是在部门CPU版本上出现。在CAN接收中断中打印log,能发现log是按照接收数据的时间打印的。
驱动(rockchip_canfd.c)中关闭NAPI后正常,厂家的回复是“有的产品api不同,NAPI方式并不适用”。
// SPDX-License-Identifier: GPL-2.0
/** Copyright (c) 2020 Rockchip Electronics Co. Ltd.* Rockchip CANFD driver*/#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/pinctrl/consumer.h>
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/reset.h>
#include <linux/pm_runtime.h>
#include <linux/rockchip/cpu.h>/* registers definition */
enum rockchip_canfd_reg {CAN_MODE = 0x00,CAN_CMD = 0x04,CAN_STATE = 0x08,CAN_INT = 0x0c,CAN_INT_MASK = 0x10,CAN_LOSTARB_CODE = 0x28,CAN_ERR_CODE = 0x2c,CAN_RX_ERR_CNT = 0x34,CAN_TX_ERR_CNT = 0x38,CAN_IDCODE = 0x3c,CAN_IDMASK = 0x40,CAN_TX_CHECK_FIC = 0x50,CAN_NBTP = 0x100,CAN_DBTP = 0x104,CAN_TDCR = 0x108,CAN_TSCC = 0x10c,CAN_TSCV = 0x110,CAN_TXEFC = 0x114,CAN_RXFC = 0x118,CAN_AFC = 0x11c,CAN_IDCODE0 = 0x120,CAN_IDMASK0 = 0x124,CAN_IDCODE1 = 0x128,CAN_IDMASK1 = 0x12c,CAN_IDCODE2 = 0x130,CAN_IDMASK2 = 0x134,CAN_IDCODE3 = 0x138,CAN_IDMASK3 = 0x13c,CAN_IDCODE4 = 0x140,CAN_IDMASK4 = 0x144,CAN_TXFIC = 0x200,CAN_TXID = 0x204,CAN_TXDAT0 = 0x208,CAN_TXDAT1 = 0x20c,CAN_TXDAT2 = 0x210,CAN_TXDAT3 = 0x214,CAN_TXDAT4 = 0x218,CAN_TXDAT5 = 0x21c,CAN_TXDAT6 = 0x220,CAN_TXDAT7 = 0x224,CAN_TXDAT8 = 0x228,CAN_TXDAT9 = 0x22c,CAN_TXDAT10 = 0x230,CAN_TXDAT11 = 0x234,CAN_TXDAT12 = 0x238,CAN_TXDAT13 = 0x23c,CAN_TXDAT14 = 0x240,CAN_TXDAT15 = 0x244,CAN_RXFIC = 0x300,CAN_RXID = 0x304,CAN_RXTS = 0x308,CAN_RXDAT0 = 0x30c,CAN_RXDAT1 = 0x310,CAN_RXDAT2 = 0x314,CAN_RXDAT3 = 0x318,CAN_RXDAT4 = 0x31c,CAN_RXDAT5 = 0x320,CAN_RXDAT6 = 0x324,CAN_RXDAT7 = 0x328,CAN_RXDAT8 = 0x32c,CAN_RXDAT9 = 0x330,CAN_RXDAT10 = 0x334,CAN_RXDAT11 = 0x338,CAN_RXDAT12 = 0x33c,CAN_RXDAT13 = 0x340,CAN_RXDAT14 = 0x344,CAN_RXDAT15 = 0x348,CAN_RXFRD = 0x400,CAN_TXEFRD = 0x500,
};enum {ROCKCHIP_CANFD_MODE = 0,ROCKCHIP_CAN_MODE,ROCKCHIP_RK3568_CAN_MODE,ROCKCHIP_RK3568_CAN_MODE_V2,
};#define DATE_LENGTH_12_BYTE (0x9)
#define DATE_LENGTH_16_BYTE (0xa)
#define DATE_LENGTH_20_BYTE (0xb)
#define DATE_LENGTH_24_BYTE (0xc)
#define DATE_LENGTH_32_BYTE (0xd)
#define DATE_LENGTH_48_BYTE (0xe)
#define DATE_LENGTH_64_BYTE (0xf)#define CAN_TX0_REQ BIT(0)
#define CAN_TX1_REQ BIT(1)
#define CAN_TX_REQ_FULL ((CAN_TX0_REQ) | (CAN_TX1_REQ))#define MODE_FDOE BIT(15)
#define MODE_BRSD BIT(13)
#define MODE_SPACE_RX BIT(12)
#define MODE_AUTO_RETX BIT(10)
#define MODE_RXSORT BIT(7)
#define MODE_TXORDER BIT(6)
#define MODE_RXSTX BIT(5)
#define MODE_LBACK BIT(4)
#define MODE_SILENT BIT(3)
#define MODE_SELF_TEST BIT(2)
#define MODE_SLEEP BIT(1)
#define RESET_MODE 0
#define WORK_MODE BIT(0)#define RX_FINISH_INT BIT(0)
#define TX_FINISH_INT BIT(1)
#define ERR_WARN_INT BIT(2)
#define RX_BUF_OV_INT BIT(3)
#define PASSIVE_ERR_INT BIT(4)
#define TX_LOSTARB_INT BIT(5)
#define BUS_ERR_INT BIT(6)
#define RX_FIFO_FULL_INT BIT(7)
#define RX_FIFO_OV_INT BIT(8)
#define BUS_OFF_INT BIT(9)
#define BUS_OFF_RECOVERY_INT BIT(10)
#define TSC_OV_INT BIT(11)
#define TXE_FIFO_OV_INT BIT(12)
#define TXE_FIFO_FULL_INT BIT(13)
#define WAKEUP_INT BIT(14)#define ERR_TYPE_MASK GENMASK(28, 26)
#define ERR_TYPE_SHIFT 26
#define BIT_ERR 0
#define STUFF_ERR 1
#define FORM_ERR 2
#define ACK_ERR 3
#define CRC_ERR 4
#define ERR_DIR_RX BIT(25)
#define ERR_LOC_MASK GENMASK(15, 0)/* Nominal Bit Timing & Prescaler Register (NBTP) */
#define NBTP_MODE_3_SAMPLES BIT(31)
#define NBTP_NSJW_SHIFT 24
#define NBTP_NSJW_MASK (0x7f << NBTP_NSJW_SHIFT)
#define NBTP_NBRP_SHIFT 16
#define NBTP_NBRP_MASK (0xff << NBTP_NBRP_SHIFT)
#define NBTP_NTSEG2_SHIFT 8
#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT)
#define NBTP_NTSEG1_SHIFT 0
#define NBTP_NTSEG1_MASK (0x7f << NBTP_NTSEG1_SHIFT)/* Data Bit Timing & Prescaler Register (DBTP) */
#define DBTP_MODE_3_SAMPLES BIT(21)
#define DBTP_DSJW_SHIFT 17
#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT)
#define DBTP_DBRP_SHIFT 9
#define DBTP_DBRP_MASK (0xff << DBTP_DBRP_SHIFT)
#define DBTP_DTSEG2_SHIFT 5
#define DBTP_DTSEG2_MASK (0xf << DBTP_DTSEG2_SHIFT)
#define DBTP_DTSEG1_SHIFT 0
#define DBTP_DTSEG1_MASK (0x1f << DBTP_DTSEG1_SHIFT)/* Transmitter Delay Compensation Register (TDCR) */
#define TDCR_TDCO_SHIFT 1
#define TDCR_TDCO_MASK (0x3f << TDCR_TDCO_SHIFT)
#define TDCR_TDC_ENABLE BIT(0)#define TX_FD_ENABLE BIT(5)
#define TX_FD_BRS_ENABLE BIT(4)#define FIFO_ENABLE BIT(0)
#define RX_FIFO_CNT0_SHIFT 4
#define RX_FIFO_CNT0_MASK (0x7 << RX_FIFO_CNT0_SHIFT)
#define RX_FIFO_CNT1_SHIFT 5
#define RX_FIFO_CNT1_MASK (0x7 << RX_FIFO_CNT1_SHIFT)#define FORMAT_SHIFT 7
#define FORMAT_MASK (0x1 << FORMAT_SHIFT)
#define RTR_SHIFT 6
#define RTR_MASK (0x1 << RTR_SHIFT)
#define FDF_SHIFT 5
#define FDF_MASK (0x1 << FDF_SHIFT)
#define BRS_SHIFT 4
#define BRS_MASK (0x1 << BRS_SHIFT)
#define DLC_SHIFT 0
#define DLC_MASK (0xF << DLC_SHIFT)#define CAN_RF_SIZE 0x48
#define CAN_TEF_SIZE 0x8
#define CAN_TXEFRD_OFFSET(n) (CAN_TXEFRD + CAN_TEF_SIZE * (n))
#define CAN_RXFRD_OFFSET(n) (CAN_RXFRD + CAN_RF_SIZE * (n))#define CAN_RX_FILTER_MASK 0x1fffffff
#define NOACK_ERR_FLAG 0xc200800
#define CAN_BUSOFF_FLAG 0x20#define DRV_NAME "rockchip_canfd"/* rockchip_canfd private data structure */struct rockchip_canfd {struct can_priv can;struct device *dev;struct napi_struct napi;struct clk_bulk_data *clks;int num_clks;struct reset_control *reset;void __iomem *base;u32 irqstatus;unsigned long mode;int rx_fifo_shift;u32 rx_fifo_mask;bool txtorx;u32 tx_invalid[4];struct delayed_work tx_err_work;u32 noack_cnt;u32 delay_time_ms;
};static inline u32 rockchip_canfd_read(const struct rockchip_canfd *priv,enum rockchip_canfd_reg reg)
{return readl(priv->base + reg);
}static inline void rockchip_canfd_write(const struct rockchip_canfd *priv,enum rockchip_canfd_reg reg, u32 val)
{writel(val, priv->base + reg);
}static const struct can_bittiming_const rockchip_canfd_bittiming_const = {.name = DRV_NAME,.tseg1_min = 1,.tseg1_max = 128,.tseg2_min = 1,.tseg2_max = 128,.sjw_max = 128,.brp_min = 1,.brp_max = 256,.brp_inc = 2,
};static const struct can_bittiming_const rockchip_canfd_data_bittiming_const = {.name = DRV_NAME,.tseg1_min = 1,.tseg1_max = 32,.tseg2_min = 1,.tseg2_max = 16,.sjw_max = 16,.brp_min = 1,.brp_max = 256,.brp_inc = 2,
};static int set_reset_mode(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);reset_control_assert(rcan->reset);udelay(2);reset_control_deassert(rcan->reset);rockchip_canfd_write(rcan, CAN_MODE, 0);netdev_dbg(ndev, "%s MODE=0x%08x\n", __func__,rockchip_canfd_read(rcan, CAN_MODE));return 0;
}static int set_normal_mode(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);u32 val;val = rockchip_canfd_read(rcan, CAN_MODE);val |= WORK_MODE;rockchip_canfd_write(rcan, CAN_MODE, val);netdev_dbg(ndev, "%s MODE=0x%08x\n", __func__,rockchip_canfd_read(rcan, CAN_MODE));return 0;
}/* bittiming is called in reset_mode only */
static int rockchip_canfd_set_bittiming(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);const struct can_bittiming *bt = &rcan->can.bittiming;const struct can_bittiming *dbt = &rcan->can.data_bittiming;u16 brp, sjw, tseg1, tseg2;u32 reg_btp;brp = (bt->brp >> 1) - 1;sjw = bt->sjw - 1;tseg1 = bt->prop_seg + bt->phase_seg1 - 1;tseg2 = bt->phase_seg2 - 1;reg_btp = (brp << NBTP_NBRP_SHIFT) | (sjw << NBTP_NSJW_SHIFT) |(tseg1 << NBTP_NTSEG1_SHIFT) |(tseg2 << NBTP_NTSEG2_SHIFT);if (rcan->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)reg_btp |= NBTP_MODE_3_SAMPLES;rockchip_canfd_write(rcan, CAN_NBTP, reg_btp);if (rcan->can.ctrlmode & CAN_CTRLMODE_FD) {reg_btp = 0;brp = (dbt->brp >> 1) - 1;sjw = dbt->sjw - 1;tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;tseg2 = dbt->phase_seg2 - 1;if (dbt->bitrate > 2200000) {u32 tdco;/* Equation based on Bosch's ROCKCHIP_CAN User Manual's* Transmitter Delay Compensation Section*/tdco = (rcan->can.clock.freq / dbt->bitrate) * 2 / 3;/* Max valid TDCO value is 63 */if (tdco > 63)tdco = 63;rockchip_canfd_write(rcan, CAN_TDCR,(tdco << TDCR_TDCO_SHIFT) |TDCR_TDC_ENABLE);}reg_btp |= (brp << DBTP_DBRP_SHIFT) |(sjw << DBTP_DSJW_SHIFT) |(tseg1 << DBTP_DTSEG1_SHIFT) |(tseg2 << DBTP_DTSEG2_SHIFT);if (rcan->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)reg_btp |= DBTP_MODE_3_SAMPLES;rockchip_canfd_write(rcan, CAN_DBTP, reg_btp);}if (bt->bitrate > 200000)rcan->delay_time_ms = 1;else if (bt->bitrate > 50000)rcan->delay_time_ms = 5;elsercan->delay_time_ms = 20;netdev_dbg(ndev, "%s NBTP=0x%08x, DBTP=0x%08x, TDCR=0x%08x\n", __func__,rockchip_canfd_read(rcan, CAN_NBTP),rockchip_canfd_read(rcan, CAN_DBTP),rockchip_canfd_read(rcan, CAN_TDCR));return 0;
}static int rockchip_canfd_get_berr_counter(const struct net_device *ndev,struct can_berr_counter *bec)
{struct rockchip_canfd *rcan = netdev_priv(ndev);int err;err = pm_runtime_get_sync(rcan->dev);if (err < 0) {netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",__func__, err);return err;}bec->rxerr = rockchip_canfd_read(rcan, CAN_RX_ERR_CNT);bec->txerr = rockchip_canfd_read(rcan, CAN_TX_ERR_CNT);pm_runtime_put(rcan->dev);netdev_dbg(ndev, "%s RX_ERR_CNT=0x%08x, TX_ERR_CNT=0x%08x\n", __func__,rockchip_canfd_read(rcan, CAN_RX_ERR_CNT),rockchip_canfd_read(rcan, CAN_TX_ERR_CNT));return 0;
}static int rockchip_canfd_start(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);u32 val;/* we need to enter the reset mode */set_reset_mode(ndev);rockchip_canfd_write(rcan, CAN_INT_MASK, 0);/* RECEIVING FILTER, accept all */rockchip_canfd_write(rcan, CAN_IDCODE, 0);rockchip_canfd_write(rcan, CAN_IDMASK, CAN_RX_FILTER_MASK);rockchip_canfd_write(rcan, CAN_IDCODE0, 0);rockchip_canfd_write(rcan, CAN_IDMASK0, CAN_RX_FILTER_MASK);rockchip_canfd_write(rcan, CAN_IDCODE1, 0);rockchip_canfd_write(rcan, CAN_IDMASK1, CAN_RX_FILTER_MASK);rockchip_canfd_write(rcan, CAN_IDCODE2, 0);rockchip_canfd_write(rcan, CAN_IDMASK2, CAN_RX_FILTER_MASK);rockchip_canfd_write(rcan, CAN_IDCODE3, 0);rockchip_canfd_write(rcan, CAN_IDMASK3, CAN_RX_FILTER_MASK);rockchip_canfd_write(rcan, CAN_IDCODE4, 0);rockchip_canfd_write(rcan, CAN_IDMASK4, CAN_RX_FILTER_MASK);/* set mode */val = rockchip_canfd_read(rcan, CAN_MODE);/* rx fifo enable */rockchip_canfd_write(rcan, CAN_RXFC,rockchip_canfd_read(rcan, CAN_RXFC) | FIFO_ENABLE);/* Mode */val |= MODE_FDOE;/* Loopback Mode */if (rcan->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)val |= MODE_SELF_TEST | MODE_LBACK;/* Listen-only mode */if (rcan->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)val |= MODE_SILENT;rockchip_canfd_write(rcan, CAN_MODE, val);rockchip_canfd_set_bittiming(ndev);set_normal_mode(ndev);rcan->can.state = CAN_STATE_ERROR_ACTIVE;netdev_dbg(ndev, "%s MODE=0x%08x, INT_MASK=0x%08x\n", __func__,rockchip_canfd_read(rcan, CAN_MODE),rockchip_canfd_read(rcan, CAN_INT_MASK));return 0;
}static int rockchip_canfd_stop(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);rcan->can.state = CAN_STATE_STOPPED;/* we need to enter reset mode */set_reset_mode(ndev);/* disable all interrupts */rockchip_canfd_write(rcan, CAN_INT_MASK, 0xffff);netdev_dbg(ndev, "%s MODE=0x%08x, INT_MASK=0x%08x\n", __func__,rockchip_canfd_read(rcan, CAN_MODE),rockchip_canfd_read(rcan, CAN_INT_MASK));return 0;
}static int rockchip_canfd_set_mode(struct net_device *ndev,enum can_mode mode)
{int err;switch (mode) {case CAN_MODE_START:err = rockchip_canfd_start(ndev);if (err) {netdev_err(ndev, "starting CAN controller failed!\n");return err;}if (netif_queue_stopped(ndev))netif_wake_queue(ndev);break;default:return -EOPNOTSUPP;}return 0;
}static void rockchip_canfd_tx_err_delay_work(struct work_struct *work)
{struct rockchip_canfd *rcan =container_of(work, struct rockchip_canfd, tx_err_work.work);struct net_device *ndev = dev_get_drvdata(rcan->dev);rockchip_canfd_write(rcan, CAN_MODE,rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX);rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ);rockchip_canfd_write(rcan, CAN_MODE,rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX));rcan->noack_cnt++;schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms));if (rcan->noack_cnt > 50) {cancel_delayed_work(&rcan->tx_err_work);rockchip_canfd_write(rcan, CAN_INT_MASK, 0xffff);can_bus_off(ndev);rcan->noack_cnt = 0;}
}/* transmit a CAN message* message layout in the sk_buff should be like this:* xx xx xx xx ff ll 00 11 22 33 44 55 66 77* [ can_id ] [flags] [len] [can data (up to 8 bytes]*/
static int rockchip_canfd_start_xmit(struct sk_buff *skb,struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);struct canfd_frame *cf = (struct canfd_frame *)skb->data;u32 id, dlc;u32 cmd = CAN_TX0_REQ;int i;unsigned long flags;if (can_dropped_invalid_skb(ndev, skb))return NETDEV_TX_OK;netif_stop_queue(ndev);if (rockchip_canfd_read(rcan, CAN_CMD) & CAN_TX0_REQ)cmd = CAN_TX1_REQ;/* Watch carefully on the bit sequence */if (cf->can_id & CAN_EFF_FLAG) {/* Extended CAN ID format */id = cf->can_id & CAN_EFF_MASK;dlc = can_len2dlc(cf->len) & DLC_MASK;dlc |= FORMAT_MASK;/* Extended frames remote TX request */if (cf->can_id & CAN_RTR_FLAG)dlc |= RTR_MASK;} else {/* Standard CAN ID format */id = cf->can_id & CAN_SFF_MASK;dlc = can_len2dlc(cf->len) & DLC_MASK;/* Standard frames remote TX request */if (cf->can_id & CAN_RTR_FLAG)dlc |= RTR_MASK;}if ((rcan->can.ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) {dlc |= TX_FD_ENABLE;if (cf->flags & CANFD_BRS)dlc |= TX_FD_BRS_ENABLE;}if (rcan->txtorx && rcan->mode <= ROCKCHIP_RK3568_CAN_MODE && cf->can_id & CAN_EFF_FLAG)rockchip_canfd_write(rcan, CAN_MODE,rockchip_canfd_read(rcan, CAN_MODE) | MODE_RXSTX);elserockchip_canfd_write(rcan, CAN_MODE,rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_RXSTX));if (!rcan->txtorx && rcan->mode <= ROCKCHIP_RK3568_CAN_MODE && cf->can_id & CAN_EFF_FLAG) {/* Two frames are sent consecutively.* Before the first frame is tx finished,* the register of the second frame is configured.* Don't be interrupted in the middle.*/local_irq_save(flags);rockchip_canfd_write(rcan, CAN_TXID, rcan->tx_invalid[1]);rockchip_canfd_write(rcan, CAN_TXFIC, rcan->tx_invalid[0]);rockchip_canfd_write(rcan, CAN_TXDAT0, rcan->tx_invalid[2]);rockchip_canfd_write(rcan, CAN_TXDAT1, rcan->tx_invalid[3]);rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ);rockchip_canfd_write(rcan, CAN_TXID, id);rockchip_canfd_write(rcan, CAN_TXFIC, dlc);for (i = 0; i < cf->len; i += 4)rockchip_canfd_write(rcan, CAN_TXDAT0 + i,*(u32 *)(cf->data + i));can_put_echo_skb(skb, ndev, 0);rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ);local_irq_restore(flags);return NETDEV_TX_OK;}rockchip_canfd_write(rcan, CAN_TXID, id);rockchip_canfd_write(rcan, CAN_TXFIC, dlc);for (i = 0; i < cf->len; i += 4)rockchip_canfd_write(rcan, CAN_TXDAT0 + i,*(u32 *)(cf->data + i));can_put_echo_skb(skb, ndev, 0);rockchip_canfd_write(rcan, CAN_MODE,rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX);rockchip_canfd_write(rcan, CAN_CMD, cmd);rockchip_canfd_write(rcan, CAN_MODE,rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX));schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms));return NETDEV_TX_OK;
}static int rockchip_canfd_rx(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);struct net_device_stats *stats = &ndev->stats;struct canfd_frame *cf;struct sk_buff *skb;u32 id_rockchip_canfd, dlc;int i = 0;u32 __maybe_unused ts, ret;u32 data[16];dlc = rockchip_canfd_read(rcan, CAN_RXFRD);id_rockchip_canfd = rockchip_canfd_read(rcan, CAN_RXFRD);ts = rockchip_canfd_read(rcan, CAN_RXFRD);for (i = 0; i < ARRAY_SIZE(data); i++)data[i] = rockchip_canfd_read(rcan, CAN_RXFRD);if (rcan->mode <= ROCKCHIP_RK3568_CAN_MODE) {/* may be an empty frame */if (!dlc && !id_rockchip_canfd)return 1;if (rcan->txtorx) {if (rockchip_canfd_read(rcan, CAN_TX_CHECK_FIC) & FORMAT_MASK) {ret = rockchip_canfd_read(rcan, CAN_TXID) & CAN_SFF_MASK;if ((id_rockchip_canfd == ret) && !(dlc & FORMAT_MASK))rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC,ts | CAN_TX0_REQ);return 1;}}}/* create zero'ed CAN frame buffer */if (dlc & FDF_MASK)skb = alloc_canfd_skb(ndev, &cf);elseskb = alloc_can_skb(ndev, (struct can_frame **)&cf);if (!skb) {stats->rx_dropped++;return 1;}/* Change CAN data length format to socketCAN data format */if (dlc & FDF_MASK)cf->len = can_dlc2len(dlc & DLC_MASK);elsecf->len = get_can_dlc(dlc & DLC_MASK);/* Change CAN ID format to socketCAN ID format */if (dlc & FORMAT_MASK) {/* The received frame is an Extended format frame */cf->can_id = id_rockchip_canfd;cf->can_id |= CAN_EFF_FLAG;if (dlc & RTR_MASK)cf->can_id |= CAN_RTR_FLAG;} else {/* The received frame is a standard format frame */cf->can_id = id_rockchip_canfd;if (dlc & RTR_MASK)cf->can_id |= CAN_RTR_FLAG;}if (dlc & BRS_MASK)cf->flags |= CANFD_BRS;if (!(cf->can_id & CAN_RTR_FLAG)) {/* Change CAN data format to socketCAN data format */for (i = 0; i < cf->len; i += 4)*(u32 *)(cf->data + i) = data[i / 4];}stats->rx_packets++;stats->rx_bytes += cf->len;netif_rx(skb);can_led_event(ndev, CAN_LED_EVENT_RX);return 1;
}static int rockchip_canfd_get_rx_fifo_cnt(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);int quota = 0;if (read_poll_timeout_atomic(rockchip_canfd_read, quota,(quota & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift,0, 500000, false, rcan, CAN_RXFC))netdev_dbg(ndev, "Warning: get fifo cnt failed\n");quota = (quota & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift;return quota;
}/* rockchip_canfd_rx_poll - Poll routine for rx packets (NAPI)* @napi: napi structure pointer* @quota: Max number of rx packets to be processed.** This is the poll routine for rx part.* It will process the packets maximux quota value.** Return: number of packets received*/
static int rockchip_canfd_rx_poll(struct napi_struct *napi, int quota)
{struct net_device *ndev = napi->dev;struct rockchip_canfd *rcan = netdev_priv(ndev);int work_done = 0;quota = rockchip_canfd_get_rx_fifo_cnt(ndev);if (quota > 6)quota = 6;if (quota) {while (work_done < quota)work_done += rockchip_canfd_rx(ndev);}if (work_done)can_led_event(ndev, CAN_LED_EVENT_RX);if (work_done < 6) {napi_complete_done(napi, work_done);rockchip_canfd_write(rcan, CAN_INT_MASK, 0);}return work_done;
}static void rockchip_canfd_tx_retry(struct net_device *ndev, u32 isr)
{struct rockchip_canfd *rcan = netdev_priv(ndev);u32 err_code = rockchip_canfd_read(rcan, CAN_ERR_CODE);u32 data[4], mode;int i = 0;if ((isr & TX_LOSTARB_INT) || ((!(err_code & 0x2000000)) && (err_code & 0x1ff0000))) {mode = rockchip_canfd_read(rcan, CAN_MODE);for (i = 0; i < ARRAY_SIZE(data); i++)data[i] = rockchip_canfd_read(rcan, CAN_TXFIC + i * 4);rockchip_canfd_write(rcan, CAN_INT_MASK, 0xffff);rockchip_canfd_start(ndev);rockchip_canfd_write(rcan, CAN_MODE, mode);for (i = 0; i < ARRAY_SIZE(data); i++)rockchip_canfd_write(rcan, CAN_TXFIC + i * 4, data[i]);}
}static int rockchip_canfd_err(struct net_device *ndev, u32 isr)
{struct rockchip_canfd *rcan = netdev_priv(ndev);struct net_device_stats *stats = &ndev->stats;struct can_frame *cf;struct sk_buff *skb;unsigned int rxerr, txerr;u32 sta_reg;skb = alloc_can_err_skb(ndev, &cf);rxerr = rockchip_canfd_read(rcan, CAN_RX_ERR_CNT);txerr = rockchip_canfd_read(rcan, CAN_TX_ERR_CNT);sta_reg = rockchip_canfd_read(rcan, CAN_STATE);if (skb) {cf->data[6] = txerr;cf->data[7] = rxerr;}if (isr & BUS_OFF_INT) {rcan->can.state = CAN_STATE_BUS_OFF;rcan->can.can_stats.bus_off++;cf->can_id |= CAN_ERR_BUSOFF;} else if (isr & ERR_WARN_INT) {rcan->can.can_stats.error_warning++;rcan->can.state = CAN_STATE_ERROR_WARNING;/* error warning state */if (likely(skb)) {cf->can_id |= CAN_ERR_CRTL;cf->data[1] = (txerr > rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING;cf->data[6] = txerr;cf->data[7] = rxerr;}} else if (isr & PASSIVE_ERR_INT) {rcan->can.can_stats.error_passive++;rcan->can.state = CAN_STATE_ERROR_PASSIVE;/* error passive state */cf->can_id |= CAN_ERR_CRTL;cf->data[1] = (txerr > rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING;cf->data[6] = txerr;cf->data[7] = rxerr;}if (rcan->can.state >= CAN_STATE_BUS_OFF ||((sta_reg & CAN_BUSOFF_FLAG) == CAN_BUSOFF_FLAG)) {cancel_delayed_work(&rcan->tx_err_work);rockchip_canfd_write(rcan, CAN_INT_MASK, 0xffff);can_bus_off(ndev);}stats->rx_packets++;stats->rx_bytes += cf->can_dlc;netif_rx(skb);return 0;
}static irqreturn_t rockchip_canfd_interrupt(int irq, void *dev_id)
{struct net_device *ndev = (struct net_device *)dev_id;struct rockchip_canfd *rcan = netdev_priv(ndev);struct net_device_stats *stats = &ndev->stats;u32 err_int = ERR_WARN_INT | RX_BUF_OV_INT | PASSIVE_ERR_INT |BUS_ERR_INT | BUS_OFF_INT;u32 isr;u32 dlc = 0;u32 quota, work_done = 0;isr = rockchip_canfd_read(rcan, CAN_INT);if (isr & TX_FINISH_INT) {cancel_delayed_work(&rcan->tx_err_work);dlc = rockchip_canfd_read(rcan, CAN_TXFIC);/* transmission complete interrupt */if (dlc & FDF_MASK)stats->tx_bytes += can_dlc2len(dlc & DLC_MASK);elsestats->tx_bytes += (dlc & DLC_MASK);stats->tx_packets++;if (rcan->txtorx && rcan->mode <= ROCKCHIP_RK3568_CAN_MODE && dlc & FORMAT_MASK) {rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, FORMAT_MASK);quota = rockchip_canfd_get_rx_fifo_cnt(ndev);if (quota) {while (work_done < quota)work_done += rockchip_canfd_rx(ndev);}if (rockchip_canfd_read(rcan, CAN_TX_CHECK_FIC) & CAN_TX0_REQ)rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ);rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, 0);}if (read_poll_timeout_atomic(rockchip_canfd_read, quota,!(quota & 0x3),0, 5000000, false, rcan, CAN_CMD))netdev_err(ndev, "Warning: wait tx req timeout!\n");rockchip_canfd_write(rcan, CAN_CMD, 0);can_get_echo_skb(ndev, 0);netif_wake_queue(ndev);can_led_event(ndev, CAN_LED_EVENT_TX);rcan->noack_cnt = 0;}if ((isr & RX_FINISH_INT) || (isr & RX_FIFO_OV_INT) || (isr & RX_FIFO_FULL_INT)) {if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2) {//rockchip_canfd_write(rcan, CAN_INT_MASK, 0x1);work_done = 0;quota = (rockchip_canfd_read(rcan, CAN_RXFC) &rcan->rx_fifo_mask) >>rcan->rx_fifo_shift;if (quota) {while (work_done < quota)work_done += rockchip_canfd_rx(ndev);}} else {work_done = 0;quota = (rockchip_canfd_read(rcan, CAN_RXFC) &rcan->rx_fifo_mask) >>rcan->rx_fifo_shift;if (quota) {while (work_done < quota)work_done += rockchip_canfd_rx(ndev);}}}if (isr & err_int) {/* error interrupt */if (rockchip_canfd_err(ndev, isr))netdev_err(ndev, "can't allocate buffer - clearing pending interrupts\n");}rockchip_canfd_tx_retry(ndev, isr);rockchip_canfd_write(rcan, CAN_INT, isr);return IRQ_HANDLED;
}static int rockchip_canfd_open(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);int err;/* common open */err = open_candev(ndev);if (err)return err;err = pm_runtime_get_sync(rcan->dev);if (err < 0) {netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",__func__, err);goto exit;}err = rockchip_canfd_start(ndev);if (err) {netdev_err(ndev, "could not start CAN peripheral\n");goto exit_can_start;}can_led_event(ndev, CAN_LED_EVENT_OPEN);
// if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2)
// napi_enable(&rcan->napi);netif_start_queue(ndev);netdev_dbg(ndev, "%s\n", __func__);return 0;exit_can_start:pm_runtime_put(rcan->dev);
exit:close_candev(ndev);return err;
}static int rockchip_canfd_close(struct net_device *ndev)
{struct rockchip_canfd *rcan = netdev_priv(ndev);netif_stop_queue(ndev);
// if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2)
// napi_disable(&rcan->napi);rockchip_canfd_stop(ndev);close_candev(ndev);can_led_event(ndev, CAN_LED_EVENT_STOP);pm_runtime_put(rcan->dev);cancel_delayed_work_sync(&rcan->tx_err_work);netdev_dbg(ndev, "%s\n", __func__);return 0;
}static const struct net_device_ops rockchip_canfd_netdev_ops = {.ndo_open = rockchip_canfd_open,.ndo_stop = rockchip_canfd_close,.ndo_start_xmit = rockchip_canfd_start_xmit,.ndo_change_mtu = can_change_mtu,
};/*** rockchip_canfd_suspend - Suspend method for the driver* @dev: Address of the device structure** Put the driver into low power mode.* Return: 0 on success and failure value on error*/
static int __maybe_unused rockchip_canfd_suspend(struct device *dev)
{struct net_device *ndev = dev_get_drvdata(dev);if (netif_running(ndev)) {netif_stop_queue(ndev);netif_device_detach(ndev);rockchip_canfd_stop(ndev);}return pm_runtime_force_suspend(dev);
}/*** rockchip_canfd_resume - Resume from suspend* @dev: Address of the device structure** Resume operation after suspend.* Return: 0 on success and failure value on error*/
static int __maybe_unused rockchip_canfd_resume(struct device *dev)
{struct net_device *ndev = dev_get_drvdata(dev);int ret;ret = pm_runtime_force_resume(dev);if (ret) {dev_err(dev, "pm_runtime_force_resume failed on resume\n");return ret;}if (netif_running(ndev)) {ret = rockchip_canfd_start(ndev);if (ret) {dev_err(dev, "rockchip_canfd_chip_start failed on resume\n");return ret;}netif_device_attach(ndev);netif_start_queue(ndev);}return 0;
}/*** rockchip_canfd_runtime_suspend - Runtime suspend method for the driver* @dev: Address of the device structure** Put the driver into low power mode.* Return: 0 always*/
static int __maybe_unused rockchip_canfd_runtime_suspend(struct device *dev)
{struct net_device *ndev = dev_get_drvdata(dev);struct rockchip_canfd *rcan = netdev_priv(ndev);clk_bulk_disable_unprepare(rcan->num_clks, rcan->clks);return 0;
}/*** rockchip_canfd_runtime_resume - Runtime resume from suspend* @dev: Address of the device structure** Resume operation after suspend.* Return: 0 on success and failure value on error*/
static int __maybe_unused rockchip_canfd_runtime_resume(struct device *dev)
{struct net_device *ndev = dev_get_drvdata(dev);struct rockchip_canfd *rcan = netdev_priv(ndev);int ret;ret = clk_bulk_prepare_enable(rcan->num_clks, rcan->clks);if (ret) {dev_err(dev, "Cannot enable clock.\n");return ret;}return 0;
}static const struct dev_pm_ops rockchip_canfd_dev_pm_ops = {SET_SYSTEM_SLEEP_PM_OPS(rockchip_canfd_suspend, rockchip_canfd_resume)SET_RUNTIME_PM_OPS(rockchip_canfd_runtime_suspend,rockchip_canfd_runtime_resume, NULL)
};static const struct of_device_id rockchip_canfd_of_match[] = {{.compatible = "rockchip,canfd-1.0",.data = (void *)ROCKCHIP_CANFD_MODE},{.compatible = "rockchip,can-2.0",.data = (void *)ROCKCHIP_CAN_MODE},{.compatible = "rockchip,rk3568-can-2.0",.data = (void *)ROCKCHIP_RK3568_CAN_MODE},{},
};
MODULE_DEVICE_TABLE(of, rockchip_canfd_of_match);static int rockchip_canfd_probe(struct platform_device *pdev)
{struct net_device *ndev;struct rockchip_canfd *rcan;struct resource *res;void __iomem *addr;int err, irq;irq = platform_get_irq(pdev, 0);if (irq < 0) {dev_err(&pdev->dev, "could not get a valid irq\n");return -ENODEV;}res = platform_get_resource(pdev, IORESOURCE_MEM, 0);addr = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(addr))return -EBUSY;ndev = alloc_candev(sizeof(struct rockchip_canfd), 1);if (!ndev) {dev_err(&pdev->dev, "could not allocate memory for CANFD device\n");return -ENOMEM;}rcan = netdev_priv(ndev);/* register interrupt handler */err = devm_request_irq(&pdev->dev, irq, rockchip_canfd_interrupt,0, ndev->name, ndev);if (err) {dev_err(&pdev->dev, "request_irq err: %d\n", err);return err;}rcan->reset = devm_reset_control_array_get(&pdev->dev, false, false);if (IS_ERR(rcan->reset)) {if (PTR_ERR(rcan->reset) != -EPROBE_DEFER)dev_err(&pdev->dev, "failed to get canfd reset lines\n");return PTR_ERR(rcan->reset);}rcan->num_clks = devm_clk_bulk_get_all(&pdev->dev, &rcan->clks);if (rcan->num_clks < 1)return -ENODEV;rcan->mode = (unsigned long)of_device_get_match_data(&pdev->dev);if ((cpu_is_rk3566() || cpu_is_rk3568()) && (rockchip_get_cpu_version() == 3))rcan->mode = ROCKCHIP_RK3568_CAN_MODE_V2;rcan->base = addr;rcan->can.clock.freq = clk_get_rate(rcan->clks[0].clk);rcan->dev = &pdev->dev;rcan->can.state = CAN_STATE_STOPPED;switch (rcan->mode) {case ROCKCHIP_CANFD_MODE:rcan->can.bittiming_const = &rockchip_canfd_bittiming_const;rcan->can.data_bittiming_const = &rockchip_canfd_data_bittiming_const;rcan->can.do_set_mode = rockchip_canfd_set_mode;rcan->can.do_get_berr_counter = rockchip_canfd_get_berr_counter;rcan->can.do_set_bittiming = rockchip_canfd_set_bittiming;rcan->can.do_set_data_bittiming = rockchip_canfd_set_bittiming;rcan->can.ctrlmode = CAN_CTRLMODE_FD;/* IFI CANFD can do both Bosch FD and ISO FD */rcan->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |CAN_CTRLMODE_FD;rcan->rx_fifo_shift = RX_FIFO_CNT0_SHIFT;rcan->rx_fifo_mask = RX_FIFO_CNT0_MASK;break;case ROCKCHIP_CAN_MODE:case ROCKCHIP_RK3568_CAN_MODE:case ROCKCHIP_RK3568_CAN_MODE_V2:rcan->can.bittiming_const = &rockchip_canfd_bittiming_const;rcan->can.do_set_mode = rockchip_canfd_set_mode;rcan->can.do_get_berr_counter = rockchip_canfd_get_berr_counter;rcan->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING |CAN_CTRLMODE_LISTENONLY |CAN_CTRLMODE_LOOPBACK |CAN_CTRLMODE_3_SAMPLES;rcan->rx_fifo_shift = RX_FIFO_CNT0_SHIFT;rcan->rx_fifo_mask = RX_FIFO_CNT0_MASK;break;default:return -EINVAL;}if (rcan->mode == ROCKCHIP_CAN_MODE) {rcan->rx_fifo_shift = RX_FIFO_CNT1_SHIFT;rcan->rx_fifo_mask = RX_FIFO_CNT1_MASK;}if (device_property_read_u32_array(&pdev->dev,"rockchip,tx-invalid-info",rcan->tx_invalid, 4))rcan->txtorx = 1;if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2) {rcan->txtorx = 0;//netif_napi_add(ndev, &rcan->napi, rockchip_canfd_rx_poll, 6);}ndev->netdev_ops = &rockchip_canfd_netdev_ops;ndev->irq = irq;ndev->flags |= IFF_ECHO;rcan->can.restart_ms = 100;rcan->noack_cnt = 0;irq_set_affinity_hint(irq, get_cpu_mask(num_online_cpus() - 1));INIT_DELAYED_WORK(&rcan->tx_err_work, rockchip_canfd_tx_err_delay_work);platform_set_drvdata(pdev, ndev);SET_NETDEV_DEV(ndev, &pdev->dev);pm_runtime_enable(&pdev->dev);err = pm_runtime_get_sync(&pdev->dev);if (err < 0) {dev_err(&pdev->dev, "%s: pm_runtime_get failed(%d)\n",__func__, err);goto err_pmdisable;}err = register_candev(ndev);if (err) {dev_err(&pdev->dev, "registering %s failed (err=%d)\n",DRV_NAME, err);goto err_disableclks;}devm_can_led_init(ndev);return 0;err_disableclks:pm_runtime_put(&pdev->dev);
err_pmdisable:pm_runtime_disable(&pdev->dev);free_candev(ndev);return err;
}static int rockchip_canfd_remove(struct platform_device *pdev)
{struct net_device *ndev = platform_get_drvdata(pdev);
// struct rockchip_canfd *rcan = netdev_priv(ndev);unregister_netdev(ndev);pm_runtime_disable(&pdev->dev);
// if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2)
// netif_napi_del(&rcan->napi);free_candev(ndev);return 0;
}static struct platform_driver rockchip_canfd_driver = {.driver = {.name = DRV_NAME,.pm = &rockchip_canfd_dev_pm_ops,.of_match_table = rockchip_canfd_of_match,},.probe = rockchip_canfd_probe,.remove = rockchip_canfd_remove,
};
module_platform_driver(rockchip_canfd_driver);MODULE_AUTHOR("Elaine Zhang <zhangqing@rock-chips.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Rockchip CANFD Drivers");
相关文章:

RK3568 CAN波特率500K接收数据导致CPU4满载
最近调试RK3568 CAN时发现,当CAN作为接收端,在快速接收数据时会导致cpu4满载。down掉can口或者断开外设时恢复正常。并且问题只是在部门CPU版本上出现。在CAN接收中断中打印log,能发现log是按照接收数据的时间打印的。 驱动(rockchip_canfd…...

AI实战 | 使用元器打造浪漫仪式小管家
浪漫仪式小管家 以前我们曾经打造过学习助手和待办助手,但这一次,我们决定创造一个与众不同的智能体,而浪漫将成为我们的主题。我们选择浪漫作为主题,是因为我们感到在之前的打造过程中缺乏了一些仪式感,无法给对方带来真正的惊喜。因此,这一次我们计划慢慢调试,将它发…...

什么是隐马尔可夫模型?
文章目录 一、说明二、玩具HMM:5′拼接位点识别三、那么,隐藏了什么?四、查找最佳状态路径五、超越最佳得分对齐六、制作更逼真的模型七、收获 关键词:hidden markov model 一、说明 被称为隐马尔可夫模型的统计模型是计算生物学…...
qt中使用qsqlite连接数据库,却没有在本地文件夹中生成db文件
exe运行起来之后,发现没有在exe文件夹下生成数据库文件,,之前可以,但中间莫名其妙不行了,代码如下 // 建立和SQlite数据库的连接database QSqlDatabase::addDatabase("QSQLITE");// 设置数据库文件的名字da…...
Django的‘通用视图TemplateView’
使用通用视图的好处是:如果有一个html需要展示,不需要写view视图函数,直接写好url即可。 使用通用视图的步骤如下: 1、编辑项目urls.py文件 from django.views.generic import TemplateView 在该文件的映射表中添加:…...
java功能实现在某个时间范围之内输出true,不在某个范围输出false,时间精确到分钟
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DateTimeChecker { private static final Logger log LoggerFactory.getLogger(DateTimeChecker.class); /** * 检查当前时间是否在指定的小时和分钟范围内。 * * param startHour 开…...

macbook屏幕录制技巧,这2个方法请你收好
在当今数字化时代,屏幕录制成为了一项不可或缺的技能,无论是教学演示、游戏直播,还是软件操作教程,屏幕录制都能帮助我们更直观地传达信息。MacBook作为苹果公司的标志性产品,其屏幕录制功能也备受用户关注。本文将详细…...

vue-loader
Vue Loader 是一个 webpack 的 loader,它允许你以一种名为单文件组件 (SFCs)的格式撰写 Vue 组件 起步 安装 npm install vue --save npm install webpack webpack-cli style-loader css-loader html-webpack-plugin vue-loader vue-template-compiler webpack…...

IO系列(十) -TCP 滑动窗口原理介绍(上)
一、摘要 之前在上分享网络编程知识文章的时候,有网友写下一条留言:“可以写写一篇关于 TCP 滑动窗口原理的文章吗?”。 当时没有立即回复,经过查询多方资料,发现这个 TCP 真的非常非常的复杂,就像一个清…...
IPython 使用技巧整理
IPython 是一个增强的 Python 交互式 shell,提供了许多实用的功能和特性,使得 Python 编程和数据科学工作变得更加便捷和高效。以下是一些 IPython 的使用技巧整理: 1. 自动补全和查询 Tab 补全:在 IPython 中,你可以…...

Python 引入中文py文件
目录 背景 思路 importlib介绍 使用方法 1.导入内置库 importlib.util 2.创建模块规格对象 spec importlib.util.spec_from_file_location("example_module", "example.py") 3.创建模块对象 module importlib.util.module_from_spec(spec) …...

qt 实现模拟实际物体带速度的移动(水平、垂直、斜角度)——————附带完整代码
文章目录 0 效果1 原理1.1 图片旋转1.2 物体按照现实中的实际距离带真实速度移动 2 完整实现2.1 将车辆按钮封装为一个类:2.2 调用方法 3 完整代码参考 0 效果 实现后的效果如下 可以显示属性(继承自QToolButton): 鼠标悬浮显示文字 按钮…...

驱动开发(三):内核层控制硬件层
驱动开发系列文章: 驱动开发(一):驱动代码的基本框架 驱动开发(二):创建字符设备驱动 驱动开发(三):内核层控制硬件层 ←本文 目录…...

企业邮箱大附件无法上传?无法确认接收状态?这样解决就行
Outlook邮箱作为最常用的邮箱系统,被全世界企业采用作为内部通用沟通方式,但Outlook邮箱却有着明显的使用缺陷,如邮箱大附件上传障碍及附件接收无提示等。 1、企业邮箱大附件无法上传 Outlook企业邮箱大附件的上传上限一般是50M,…...
Kotlin 数据类(Data Class)
Kotlin 数据类(Data Class)是一种特别用于持有数据的类。它们简化了数据类的创建,并提供了一些自动生成的方法。下面详细介绍 Kotlin 数据类的原理和使用方法。 数据类的定义 Kotlin 中的数据类使用 data 关键字定义。例如: da…...

gridview自带编辑功能如何判断用户修改的值的合法性
在使用GridView的编辑功能更新值时,确保输入的值合法性是十分重要的。为了实现这一点,你可以在GridView的RowUpdating事件中加入代码来检查用户输入的值。如果发现输入的值不合法,你可以取消更新操作并向用户显示错误消息。下面是如何实现的步…...

设计模式-结构型-06-桥接模式
1、传统方式解决手机操作问题 现在对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网,打电话等),如图: UML 类图 问题分析 扩展性问题(类爆炸):如果我们再…...

安泰电压放大器的选型原则是什么
电压放大器是电子电路中常用的一种器件,主要用于放大输入电压信号。在选型电压放大器时,需要考虑以下几个原则。 根据应用需求确定放大倍数。放大倍数是指输出电压与输入电压之间的倍数关系,也称为增益。不同的应用场景对放大倍数的要求不同&…...

方法分享 |公网IP怎么指定非433端口实现https访问
公网IP可以通过指定非443端口实现HTTPS访问。在网络配置中,虽然HTTPS协议默认使用443端口,但没有规定不能在其他端口上实施HTTPS服务。使用非标准端口进行HTTPS通信需要正确配置服务器和SSL证书,并确保客户端能够连接到指定的端口。下面说明如…...

vue实现拖拽元素;vuedraggable拖拽插件
效果图: 中文文档 以下代码可直接复制使用 安装依赖 npm i -S vuedraggable使用 <template><div class"container"><div>使用flex竖轴布局 <br>handle".mover" 可拖拽的class类名 <br>filter".forbid&qu…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...

Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...