From: Greg Kroah-Hartman Date: Fri, 10 Mar 2023 11:26:00 +0000 (+0100) Subject: 6.2-stable patches X-Git-Tag: v6.1.17~38 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cdf08b5727cc855950812a03c3b870fde8e1b69a;p=thirdparty%2Fkernel%2Fstable-queue.git 6.2-stable patches added patches: drm-display-dp_mst-add-drm_atomic_get_old_mst_topology_state.patch eth-fealnx-bring-back-this-old-driver.patch net-tls-avoid-hanging-tasks-on-the-tx_lock.patch vdpa-ifcvf-alloc-the-mgmt_dev-before-the-adapter.patch vdpa-ifcvf-allocate-the-adapter-in-dev_add.patch vdpa-ifcvf-decouple-config-dev-irq-requester-and-vectors-allocator-from-the-adapter.patch vdpa-ifcvf-decouple-config-irq-releaser-from-the-adapter.patch vdpa-ifcvf-decouple-config-space-ops-from-the-adapter.patch vdpa-ifcvf-decouple-hw-features-manipulators-from-the-adapter.patch vdpa-ifcvf-decouple-vq-irq-releasers-from-the-adapter.patch vdpa-ifcvf-decouple-vq-irq-requester-from-the-adapter.patch vdpa-ifcvf-ifcvf_request_irq-works-on-ifcvf_hw.patch vdpa-ifcvf-manage-ifcvf_hw-in-the-mgmt_dev.patch x86-resctl-fix-scheduler-confusion-with-current.patch --- diff --git a/queue-6.2/drm-display-dp_mst-add-drm_atomic_get_old_mst_topology_state.patch b/queue-6.2/drm-display-dp_mst-add-drm_atomic_get_old_mst_topology_state.patch new file mode 100644 index 00000000000..e0fb12e8404 --- /dev/null +++ b/queue-6.2/drm-display-dp_mst-add-drm_atomic_get_old_mst_topology_state.patch @@ -0,0 +1,111 @@ +From 9ffdb67af0ee625ae127711845532f670cc6a4e7 Mon Sep 17 00:00:00 2001 +From: Imre Deak +Date: Mon, 6 Feb 2023 13:48:55 +0200 +Subject: drm/display/dp_mst: Add drm_atomic_get_old_mst_topology_state() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Imre Deak + +commit 9ffdb67af0ee625ae127711845532f670cc6a4e7 upstream. + +Add a function to get the old MST topology state, required by a +follow-up i915 patch. + +While at it clarify the code comment of +drm_atomic_get_new_mst_topology_state() and add _new prefix +to the new state pointer to remind about its difference from the old +state. + +v2: Use old_/new_ prefixes for the state pointers. (Ville) + +Cc: Lyude Paul +Cc: Ville Syrjälä +Cc: stable@vger.kernel.org # 6.1 +Cc: dri-devel@lists.freedesktop.org +Reviewed-by: Ville Syrjälä +Reviewed-by: Lyude Paul +Acked-by: Lyude Paul +Acked-by: Daniel Vetter +Acked-by: Wayne Lin +Acked-by: Jani Nikula +Signed-off-by: Imre Deak +Link: https://patchwork.freedesktop.org/patch/msgid/20230206114856.2665066-3-imre.deak@intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/display/drm_dp_mst_topology.c | 33 ++++++++++++++++++++++---- + include/drm/display/drm_dp_mst_helper.h | 3 ++ + 2 files changed, 32 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c ++++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c +@@ -5355,27 +5355,52 @@ struct drm_dp_mst_topology_state *drm_at + EXPORT_SYMBOL(drm_atomic_get_mst_topology_state); + + /** ++ * drm_atomic_get_old_mst_topology_state: get old MST topology state in atomic state, if any ++ * @state: global atomic state ++ * @mgr: MST topology manager, also the private object in this case ++ * ++ * This function wraps drm_atomic_get_old_private_obj_state() passing in the MST atomic ++ * state vtable so that the private object state returned is that of a MST ++ * topology object. ++ * ++ * Returns: ++ * ++ * The old MST topology state, or NULL if there's no topology state for this MST mgr ++ * in the global atomic state ++ */ ++struct drm_dp_mst_topology_state * ++drm_atomic_get_old_mst_topology_state(struct drm_atomic_state *state, ++ struct drm_dp_mst_topology_mgr *mgr) ++{ ++ struct drm_private_state *old_priv_state = ++ drm_atomic_get_old_private_obj_state(state, &mgr->base); ++ ++ return old_priv_state ? to_dp_mst_topology_state(old_priv_state) : NULL; ++} ++EXPORT_SYMBOL(drm_atomic_get_old_mst_topology_state); ++ ++/** + * drm_atomic_get_new_mst_topology_state: get new MST topology state in atomic state, if any + * @state: global atomic state + * @mgr: MST topology manager, also the private object in this case + * +- * This function wraps drm_atomic_get_priv_obj_state() passing in the MST atomic ++ * This function wraps drm_atomic_get_new_private_obj_state() passing in the MST atomic + * state vtable so that the private object state returned is that of a MST + * topology object. + * + * Returns: + * +- * The MST topology state, or NULL if there's no topology state for this MST mgr ++ * The new MST topology state, or NULL if there's no topology state for this MST mgr + * in the global atomic state + */ + struct drm_dp_mst_topology_state * + drm_atomic_get_new_mst_topology_state(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr) + { +- struct drm_private_state *priv_state = ++ struct drm_private_state *new_priv_state = + drm_atomic_get_new_private_obj_state(state, &mgr->base); + +- return priv_state ? to_dp_mst_topology_state(priv_state) : NULL; ++ return new_priv_state ? to_dp_mst_topology_state(new_priv_state) : NULL; + } + EXPORT_SYMBOL(drm_atomic_get_new_mst_topology_state); + +--- a/include/drm/display/drm_dp_mst_helper.h ++++ b/include/drm/display/drm_dp_mst_helper.h +@@ -867,6 +867,9 @@ struct drm_dp_mst_topology_state * + drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr); + struct drm_dp_mst_topology_state * ++drm_atomic_get_old_mst_topology_state(struct drm_atomic_state *state, ++ struct drm_dp_mst_topology_mgr *mgr); ++struct drm_dp_mst_topology_state * + drm_atomic_get_new_mst_topology_state(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr); + struct drm_dp_mst_atomic_payload * diff --git a/queue-6.2/eth-fealnx-bring-back-this-old-driver.patch b/queue-6.2/eth-fealnx-bring-back-this-old-driver.patch new file mode 100644 index 00000000000..4c7b35b3f26 --- /dev/null +++ b/queue-6.2/eth-fealnx-bring-back-this-old-driver.patch @@ -0,0 +1,2038 @@ +From 8f14820801042c221bb9fe51643a2585cac5dec2 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Tue, 7 Mar 2023 09:19:30 -0800 +Subject: eth: fealnx: bring back this old driver + +From: Jakub Kicinski + +commit 8f14820801042c221bb9fe51643a2585cac5dec2 upstream. + +This reverts commit d5e2d038dbece821f1af57acbeded3aa9a1832c1. + +We have a report of this chip being used on a + + SURECOM EP-320X-S 100/10M Ethernet PCI Adapter + +which could still have been purchased in some parts +of the world 3 years ago. + +Cc: stable@vger.kernel.org +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217151 +Fixes: d5e2d038dbec ("eth: fealnx: delete the driver for Myson MTD-800") +Link: https://lore.kernel.org/r/20230307171930.4008454-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + arch/mips/configs/mtx1_defconfig | 1 + arch/powerpc/configs/ppc6xx_defconfig | 1 + drivers/net/ethernet/Kconfig | 10 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/fealnx.c | 1953 ++++++++++++++++++++++++++++++++++ + 5 files changed, 1966 insertions(+) + create mode 100644 drivers/net/ethernet/fealnx.c + +--- a/arch/mips/configs/mtx1_defconfig ++++ b/arch/mips/configs/mtx1_defconfig +@@ -284,6 +284,7 @@ CONFIG_IXGB=m + CONFIG_SKGE=m + CONFIG_SKY2=m + CONFIG_MYRI10GE=m ++CONFIG_FEALNX=m + CONFIG_NATSEMI=m + CONFIG_NS83820=m + CONFIG_S2IO=m +--- a/arch/powerpc/configs/ppc6xx_defconfig ++++ b/arch/powerpc/configs/ppc6xx_defconfig +@@ -461,6 +461,7 @@ CONFIG_MV643XX_ETH=m + CONFIG_SKGE=m + CONFIG_SKY2=m + CONFIG_MYRI10GE=m ++CONFIG_FEALNX=m + CONFIG_NATSEMI=m + CONFIG_NS83820=m + CONFIG_PCMCIA_AXNET=m +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -132,6 +132,16 @@ source "drivers/net/ethernet/mscc/Kconfi + source "drivers/net/ethernet/microsoft/Kconfig" + source "drivers/net/ethernet/moxa/Kconfig" + source "drivers/net/ethernet/myricom/Kconfig" ++ ++config FEALNX ++ tristate "Myson MTD-8xx PCI Ethernet support" ++ depends on PCI ++ select CRC32 ++ select MII ++ help ++ Say Y here to support the Myson MTD-800 family of PCI-based Ethernet ++ cards. ++ + source "drivers/net/ethernet/ni/Kconfig" + source "drivers/net/ethernet/natsemi/Kconfig" + source "drivers/net/ethernet/neterion/Kconfig" +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -64,6 +64,7 @@ obj-$(CONFIG_NET_VENDOR_MICROCHIP) += mi + obj-$(CONFIG_NET_VENDOR_MICROSEMI) += mscc/ + obj-$(CONFIG_NET_VENDOR_MOXART) += moxa/ + obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/ ++obj-$(CONFIG_FEALNX) += fealnx.o + obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/ + obj-$(CONFIG_NET_VENDOR_NETERION) += neterion/ + obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/ +--- /dev/null ++++ b/drivers/net/ethernet/fealnx.c +@@ -0,0 +1,1953 @@ ++/* ++ Written 1998-2000 by Donald Becker. ++ ++ This software may be used and distributed according to the terms of ++ the GNU General Public License (GPL), incorporated herein by reference. ++ Drivers based on or derived from this code fall under the GPL and must ++ retain the authorship, copyright and license notice. This file is not ++ a complete program and may only be used when the entire operating ++ system is licensed under the GPL. ++ ++ The author may be reached as becker@scyld.com, or C/O ++ Scyld Computing Corporation ++ 410 Severn Ave., Suite 210 ++ Annapolis MD 21403 ++ ++ Support information and updates available at ++ http://www.scyld.com/network/pci-skeleton.html ++ ++ Linux kernel updates: ++ ++ Version 2.51, Nov 17, 2001 (jgarzik): ++ - Add ethtool support ++ - Replace some MII-related magic numbers with constants ++ ++*/ ++ ++#define DRV_NAME "fealnx" ++ ++static int debug; /* 1-> print debug message */ ++static int max_interrupt_work = 20; ++ ++/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ ++static int multicast_filter_limit = 32; ++ ++/* Set the copy breakpoint for the copy-only-tiny-frames scheme. */ ++/* Setting to > 1518 effectively disables this feature. */ ++static int rx_copybreak; ++ ++/* Used to pass the media type, etc. */ ++/* Both 'options[]' and 'full_duplex[]' should exist for driver */ ++/* interoperability. */ ++/* The media type is usually passed in 'options[]'. */ ++#define MAX_UNITS 8 /* More are supported, limit only on options */ ++static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; ++static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; ++ ++/* Operational parameters that are set at compile time. */ ++/* Keep the ring sizes a power of two for compile efficiency. */ ++/* The compiler will convert '%'<2^N> into a bit mask. */ ++/* Making the Tx ring too large decreases the effectiveness of channel */ ++/* bonding and packet priority. */ ++/* There are no ill effects from too-large receive rings. */ ++// 88-12-9 modify, ++// #define TX_RING_SIZE 16 ++// #define RX_RING_SIZE 32 ++#define TX_RING_SIZE 6 ++#define RX_RING_SIZE 12 ++#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct fealnx_desc) ++#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct fealnx_desc) ++ ++/* Operational parameters that usually are not changed. */ ++/* Time in jiffies before concluding the transmitter is hung. */ ++#define TX_TIMEOUT (2*HZ) ++ ++#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ ++ ++ ++/* Include files, designed to support most kernel versions 2.0.0 and later. */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include /* Processor type for cache alignment. */ ++#include ++#include ++#include ++ ++/* This driver was written to use PCI memory space, however some x86 systems ++ work only with I/O space accesses. */ ++#ifndef __alpha__ ++#define USE_IO_OPS ++#endif ++ ++/* Kernel compatibility defines, some common to David Hinds' PCMCIA package. */ ++/* This is only in the support-all-kernels source code. */ ++ ++#define RUN_AT(x) (jiffies + (x)) ++ ++MODULE_AUTHOR("Myson or whoever"); ++MODULE_DESCRIPTION("Myson MTD-8xx 100/10M Ethernet PCI Adapter Driver"); ++MODULE_LICENSE("GPL"); ++module_param(max_interrupt_work, int, 0); ++module_param(debug, int, 0); ++module_param(rx_copybreak, int, 0); ++module_param(multicast_filter_limit, int, 0); ++module_param_array(options, int, NULL, 0); ++module_param_array(full_duplex, int, NULL, 0); ++MODULE_PARM_DESC(max_interrupt_work, "fealnx maximum events handled per interrupt"); ++MODULE_PARM_DESC(debug, "fealnx enable debugging (0-1)"); ++MODULE_PARM_DESC(rx_copybreak, "fealnx copy breakpoint for copy-only-tiny-frames"); ++MODULE_PARM_DESC(multicast_filter_limit, "fealnx maximum number of filtered multicast addresses"); ++MODULE_PARM_DESC(options, "fealnx: Bits 0-3: media type, bit 17: full duplex"); ++MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)"); ++ ++enum { ++ MIN_REGION_SIZE = 136, ++}; ++ ++/* A chip capabilities table, matching the entries in pci_tbl[] above. */ ++enum chip_capability_flags { ++ HAS_MII_XCVR, ++ HAS_CHIP_XCVR, ++}; ++ ++/* 89/6/13 add, */ ++/* for different PHY */ ++enum phy_type_flags { ++ MysonPHY = 1, ++ AhdocPHY = 2, ++ SeeqPHY = 3, ++ MarvellPHY = 4, ++ Myson981 = 5, ++ LevelOnePHY = 6, ++ OtherPHY = 10, ++}; ++ ++struct chip_info { ++ char *chip_name; ++ int flags; ++}; ++ ++static const struct chip_info skel_netdrv_tbl[] = { ++ { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR }, ++ { "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR }, ++ { "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR }, ++}; ++ ++/* Offsets to the Command and Status Registers. */ ++enum fealnx_offsets { ++ PAR0 = 0x0, /* physical address 0-3 */ ++ PAR1 = 0x04, /* physical address 4-5 */ ++ MAR0 = 0x08, /* multicast address 0-3 */ ++ MAR1 = 0x0C, /* multicast address 4-7 */ ++ FAR0 = 0x10, /* flow-control address 0-3 */ ++ FAR1 = 0x14, /* flow-control address 4-5 */ ++ TCRRCR = 0x18, /* receive & transmit configuration */ ++ BCR = 0x1C, /* bus command */ ++ TXPDR = 0x20, /* transmit polling demand */ ++ RXPDR = 0x24, /* receive polling demand */ ++ RXCWP = 0x28, /* receive current word pointer */ ++ TXLBA = 0x2C, /* transmit list base address */ ++ RXLBA = 0x30, /* receive list base address */ ++ ISR = 0x34, /* interrupt status */ ++ IMR = 0x38, /* interrupt mask */ ++ FTH = 0x3C, /* flow control high/low threshold */ ++ MANAGEMENT = 0x40, /* bootrom/eeprom and mii management */ ++ TALLY = 0x44, /* tally counters for crc and mpa */ ++ TSR = 0x48, /* tally counter for transmit status */ ++ BMCRSR = 0x4c, /* basic mode control and status */ ++ PHYIDENTIFIER = 0x50, /* phy identifier */ ++ ANARANLPAR = 0x54, /* auto-negotiation advertisement and link ++ partner ability */ ++ ANEROCR = 0x58, /* auto-negotiation expansion and pci conf. */ ++ BPREMRPSR = 0x5c, /* bypass & receive error mask and phy status */ ++}; ++ ++/* Bits in the interrupt status/enable registers. */ ++/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */ ++enum intr_status_bits { ++ RFCON = 0x00020000, /* receive flow control xon packet */ ++ RFCOFF = 0x00010000, /* receive flow control xoff packet */ ++ LSCStatus = 0x00008000, /* link status change */ ++ ANCStatus = 0x00004000, /* autonegotiation completed */ ++ FBE = 0x00002000, /* fatal bus error */ ++ FBEMask = 0x00001800, /* mask bit12-11 */ ++ ParityErr = 0x00000000, /* parity error */ ++ TargetErr = 0x00001000, /* target abort */ ++ MasterErr = 0x00000800, /* master error */ ++ TUNF = 0x00000400, /* transmit underflow */ ++ ROVF = 0x00000200, /* receive overflow */ ++ ETI = 0x00000100, /* transmit early int */ ++ ERI = 0x00000080, /* receive early int */ ++ CNTOVF = 0x00000040, /* counter overflow */ ++ RBU = 0x00000020, /* receive buffer unavailable */ ++ TBU = 0x00000010, /* transmit buffer unavilable */ ++ TI = 0x00000008, /* transmit interrupt */ ++ RI = 0x00000004, /* receive interrupt */ ++ RxErr = 0x00000002, /* receive error */ ++}; ++ ++/* Bits in the NetworkConfig register, W for writing, R for reading */ ++/* FIXME: some names are invented by me. Marked with (name?) */ ++/* If you have docs and know bit names, please fix 'em */ ++enum rx_mode_bits { ++ CR_W_ENH = 0x02000000, /* enhanced mode (name?) */ ++ CR_W_FD = 0x00100000, /* full duplex */ ++ CR_W_PS10 = 0x00080000, /* 10 mbit */ ++ CR_W_TXEN = 0x00040000, /* tx enable (name?) */ ++ CR_W_PS1000 = 0x00010000, /* 1000 mbit */ ++ /* CR_W_RXBURSTMASK= 0x00000e00, Im unsure about this */ ++ CR_W_RXMODEMASK = 0x000000e0, ++ CR_W_PROM = 0x00000080, /* promiscuous mode */ ++ CR_W_AB = 0x00000040, /* accept broadcast */ ++ CR_W_AM = 0x00000020, /* accept mutlicast */ ++ CR_W_ARP = 0x00000008, /* receive runt pkt */ ++ CR_W_ALP = 0x00000004, /* receive long pkt */ ++ CR_W_SEP = 0x00000002, /* receive error pkt */ ++ CR_W_RXEN = 0x00000001, /* rx enable (unicast?) (name?) */ ++ ++ CR_R_TXSTOP = 0x04000000, /* tx stopped (name?) */ ++ CR_R_FD = 0x00100000, /* full duplex detected */ ++ CR_R_PS10 = 0x00080000, /* 10 mbit detected */ ++ CR_R_RXSTOP = 0x00008000, /* rx stopped (name?) */ ++}; ++ ++/* The Tulip Rx and Tx buffer descriptors. */ ++struct fealnx_desc { ++ s32 status; ++ s32 control; ++ u32 buffer; ++ u32 next_desc; ++ struct fealnx_desc *next_desc_logical; ++ struct sk_buff *skbuff; ++ u32 reserved1; ++ u32 reserved2; ++}; ++ ++/* Bits in network_desc.status */ ++enum rx_desc_status_bits { ++ RXOWN = 0x80000000, /* own bit */ ++ FLNGMASK = 0x0fff0000, /* frame length */ ++ FLNGShift = 16, ++ MARSTATUS = 0x00004000, /* multicast address received */ ++ BARSTATUS = 0x00002000, /* broadcast address received */ ++ PHYSTATUS = 0x00001000, /* physical address received */ ++ RXFSD = 0x00000800, /* first descriptor */ ++ RXLSD = 0x00000400, /* last descriptor */ ++ ErrorSummary = 0x80, /* error summary */ ++ RUNTPKT = 0x40, /* runt packet received */ ++ LONGPKT = 0x20, /* long packet received */ ++ FAE = 0x10, /* frame align error */ ++ CRC = 0x08, /* crc error */ ++ RXER = 0x04, /* receive error */ ++}; ++ ++enum rx_desc_control_bits { ++ RXIC = 0x00800000, /* interrupt control */ ++ RBSShift = 0, ++}; ++ ++enum tx_desc_status_bits { ++ TXOWN = 0x80000000, /* own bit */ ++ JABTO = 0x00004000, /* jabber timeout */ ++ CSL = 0x00002000, /* carrier sense lost */ ++ LC = 0x00001000, /* late collision */ ++ EC = 0x00000800, /* excessive collision */ ++ UDF = 0x00000400, /* fifo underflow */ ++ DFR = 0x00000200, /* deferred */ ++ HF = 0x00000100, /* heartbeat fail */ ++ NCRMask = 0x000000ff, /* collision retry count */ ++ NCRShift = 0, ++}; ++ ++enum tx_desc_control_bits { ++ TXIC = 0x80000000, /* interrupt control */ ++ ETIControl = 0x40000000, /* early transmit interrupt */ ++ TXLD = 0x20000000, /* last descriptor */ ++ TXFD = 0x10000000, /* first descriptor */ ++ CRCEnable = 0x08000000, /* crc control */ ++ PADEnable = 0x04000000, /* padding control */ ++ RetryTxLC = 0x02000000, /* retry late collision */ ++ PKTSMask = 0x3ff800, /* packet size bit21-11 */ ++ PKTSShift = 11, ++ TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */ ++ TBSShift = 0, ++}; ++ ++/* BootROM/EEPROM/MII Management Register */ ++#define MASK_MIIR_MII_READ 0x00000000 ++#define MASK_MIIR_MII_WRITE 0x00000008 ++#define MASK_MIIR_MII_MDO 0x00000004 ++#define MASK_MIIR_MII_MDI 0x00000002 ++#define MASK_MIIR_MII_MDC 0x00000001 ++ ++/* ST+OP+PHYAD+REGAD+TA */ ++#define OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */ ++#define OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */ ++ ++/* ------------------------------------------------------------------------- */ ++/* Constants for Myson PHY */ ++/* ------------------------------------------------------------------------- */ ++#define MysonPHYID 0xd0000302 ++/* 89-7-27 add, (begin) */ ++#define MysonPHYID0 0x0302 ++#define StatusRegister 18 ++#define SPEED100 0x0400 // bit10 ++#define FULLMODE 0x0800 // bit11 ++/* 89-7-27 add, (end) */ ++ ++/* ------------------------------------------------------------------------- */ ++/* Constants for Seeq 80225 PHY */ ++/* ------------------------------------------------------------------------- */ ++#define SeeqPHYID0 0x0016 ++ ++#define MIIRegister18 18 ++#define SPD_DET_100 0x80 ++#define DPLX_DET_FULL 0x40 ++ ++/* ------------------------------------------------------------------------- */ ++/* Constants for Ahdoc 101 PHY */ ++/* ------------------------------------------------------------------------- */ ++#define AhdocPHYID0 0x0022 ++ ++#define DiagnosticReg 18 ++#define DPLX_FULL 0x0800 ++#define Speed_100 0x0400 ++ ++/* 89/6/13 add, */ ++/* -------------------------------------------------------------------------- */ ++/* Constants */ ++/* -------------------------------------------------------------------------- */ ++#define MarvellPHYID0 0x0141 ++#define LevelOnePHYID0 0x0013 ++ ++#define MII1000BaseTControlReg 9 ++#define MII1000BaseTStatusReg 10 ++#define SpecificReg 17 ++ ++/* for 1000BaseT Control Register */ ++#define PHYAbletoPerform1000FullDuplex 0x0200 ++#define PHYAbletoPerform1000HalfDuplex 0x0100 ++#define PHY1000AbilityMask 0x300 ++ ++// for phy specific status register, marvell phy. ++#define SpeedMask 0x0c000 ++#define Speed_1000M 0x08000 ++#define Speed_100M 0x4000 ++#define Speed_10M 0 ++#define Full_Duplex 0x2000 ++ ++// 89/12/29 add, for phy specific status register, levelone phy, (begin) ++#define LXT1000_100M 0x08000 ++#define LXT1000_1000M 0x0c000 ++#define LXT1000_Full 0x200 ++// 89/12/29 add, for phy specific status register, levelone phy, (end) ++ ++/* for 3-in-1 case, BMCRSR register */ ++#define LinkIsUp2 0x00040000 ++ ++/* for PHY */ ++#define LinkIsUp 0x0004 ++ ++ ++struct netdev_private { ++ /* Descriptor rings first for alignment. */ ++ struct fealnx_desc *rx_ring; ++ struct fealnx_desc *tx_ring; ++ ++ dma_addr_t rx_ring_dma; ++ dma_addr_t tx_ring_dma; ++ ++ spinlock_t lock; ++ ++ /* Media monitoring timer. */ ++ struct timer_list timer; ++ ++ /* Reset timer */ ++ struct timer_list reset_timer; ++ int reset_timer_armed; ++ unsigned long crvalue_sv; ++ unsigned long imrvalue_sv; ++ ++ /* Frequently used values: keep some adjacent for cache effect. */ ++ int flags; ++ struct pci_dev *pci_dev; ++ unsigned long crvalue; ++ unsigned long bcrvalue; ++ unsigned long imrvalue; ++ struct fealnx_desc *cur_rx; ++ struct fealnx_desc *lack_rxbuf; ++ int really_rx_count; ++ struct fealnx_desc *cur_tx; ++ struct fealnx_desc *cur_tx_copy; ++ int really_tx_count; ++ int free_tx_count; ++ unsigned int rx_buf_sz; /* Based on MTU+slack. */ ++ ++ /* These values are keep track of the transceiver/media in use. */ ++ unsigned int linkok; ++ unsigned int line_speed; ++ unsigned int duplexmode; ++ unsigned int default_port:4; /* Last dev->if_port value. */ ++ unsigned int PHYType; ++ ++ /* MII transceiver section. */ ++ int mii_cnt; /* MII device addresses. */ ++ unsigned char phys[2]; /* MII device addresses. */ ++ struct mii_if_info mii; ++ void __iomem *mem; ++}; ++ ++ ++static int mdio_read(struct net_device *dev, int phy_id, int location); ++static void mdio_write(struct net_device *dev, int phy_id, int location, int value); ++static int netdev_open(struct net_device *dev); ++static void getlinktype(struct net_device *dev); ++static void getlinkstatus(struct net_device *dev); ++static void netdev_timer(struct timer_list *t); ++static void reset_timer(struct timer_list *t); ++static void fealnx_tx_timeout(struct net_device *dev, unsigned int txqueue); ++static void init_ring(struct net_device *dev); ++static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); ++static irqreturn_t intr_handler(int irq, void *dev_instance); ++static int netdev_rx(struct net_device *dev); ++static void set_rx_mode(struct net_device *dev); ++static void __set_rx_mode(struct net_device *dev); ++static struct net_device_stats *get_stats(struct net_device *dev); ++static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); ++static const struct ethtool_ops netdev_ethtool_ops; ++static int netdev_close(struct net_device *dev); ++static void reset_rx_descriptors(struct net_device *dev); ++static void reset_tx_descriptors(struct net_device *dev); ++ ++static void stop_nic_rx(void __iomem *ioaddr, long crvalue) ++{ ++ int delay = 0x1000; ++ iowrite32(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR); ++ while (--delay) { ++ if ( (ioread32(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP) ++ break; ++ } ++} ++ ++ ++static void stop_nic_rxtx(void __iomem *ioaddr, long crvalue) ++{ ++ int delay = 0x1000; ++ iowrite32(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR); ++ while (--delay) { ++ if ( (ioread32(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP)) ++ == (CR_R_RXSTOP+CR_R_TXSTOP) ) ++ break; ++ } ++} ++ ++static const struct net_device_ops netdev_ops = { ++ .ndo_open = netdev_open, ++ .ndo_stop = netdev_close, ++ .ndo_start_xmit = start_tx, ++ .ndo_get_stats = get_stats, ++ .ndo_set_rx_mode = set_rx_mode, ++ .ndo_eth_ioctl = mii_ioctl, ++ .ndo_tx_timeout = fealnx_tx_timeout, ++ .ndo_set_mac_address = eth_mac_addr, ++ .ndo_validate_addr = eth_validate_addr, ++}; ++ ++static int fealnx_init_one(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct netdev_private *np; ++ int i, option, err, irq; ++ static int card_idx = -1; ++ char boardname[12]; ++ void __iomem *ioaddr; ++ unsigned long len; ++ unsigned int chip_id = ent->driver_data; ++ struct net_device *dev; ++ void *ring_space; ++ dma_addr_t ring_dma; ++ u8 addr[ETH_ALEN]; ++#ifdef USE_IO_OPS ++ int bar = 0; ++#else ++ int bar = 1; ++#endif ++ ++ card_idx++; ++ sprintf(boardname, "fealnx%d", card_idx); ++ ++ option = card_idx < MAX_UNITS ? options[card_idx] : 0; ++ ++ i = pci_enable_device(pdev); ++ if (i) return i; ++ pci_set_master(pdev); ++ ++ len = pci_resource_len(pdev, bar); ++ if (len < MIN_REGION_SIZE) { ++ dev_err(&pdev->dev, ++ "region size %ld too small, aborting\n", len); ++ return -ENODEV; ++ } ++ ++ i = pci_request_regions(pdev, boardname); ++ if (i) ++ return i; ++ ++ irq = pdev->irq; ++ ++ ioaddr = pci_iomap(pdev, bar, len); ++ if (!ioaddr) { ++ err = -ENOMEM; ++ goto err_out_res; ++ } ++ ++ dev = alloc_etherdev(sizeof(struct netdev_private)); ++ if (!dev) { ++ err = -ENOMEM; ++ goto err_out_unmap; ++ } ++ SET_NETDEV_DEV(dev, &pdev->dev); ++ ++ /* read ethernet id */ ++ for (i = 0; i < 6; ++i) ++ addr[i] = ioread8(ioaddr + PAR0 + i); ++ eth_hw_addr_set(dev, addr); ++ ++ /* Reset the chip to erase previous misconfiguration. */ ++ iowrite32(0x00000001, ioaddr + BCR); ++ ++ /* Make certain the descriptor lists are aligned. */ ++ np = netdev_priv(dev); ++ np->mem = ioaddr; ++ spin_lock_init(&np->lock); ++ np->pci_dev = pdev; ++ np->flags = skel_netdrv_tbl[chip_id].flags; ++ pci_set_drvdata(pdev, dev); ++ np->mii.dev = dev; ++ np->mii.mdio_read = mdio_read; ++ np->mii.mdio_write = mdio_write; ++ np->mii.phy_id_mask = 0x1f; ++ np->mii.reg_num_mask = 0x1f; ++ ++ ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma, ++ GFP_KERNEL); ++ if (!ring_space) { ++ err = -ENOMEM; ++ goto err_out_free_dev; ++ } ++ np->rx_ring = ring_space; ++ np->rx_ring_dma = ring_dma; ++ ++ ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma, ++ GFP_KERNEL); ++ if (!ring_space) { ++ err = -ENOMEM; ++ goto err_out_free_rx; ++ } ++ np->tx_ring = ring_space; ++ np->tx_ring_dma = ring_dma; ++ ++ /* find the connected MII xcvrs */ ++ if (np->flags == HAS_MII_XCVR) { ++ int phy, phy_idx = 0; ++ ++ for (phy = 1; phy < 32 && phy_idx < ARRAY_SIZE(np->phys); ++ phy++) { ++ int mii_status = mdio_read(dev, phy, 1); ++ ++ if (mii_status != 0xffff && mii_status != 0x0000) { ++ np->phys[phy_idx++] = phy; ++ dev_info(&pdev->dev, ++ "MII PHY found at address %d, status " ++ "0x%4.4x.\n", phy, mii_status); ++ /* get phy type */ ++ { ++ unsigned int data; ++ ++ data = mdio_read(dev, np->phys[0], 2); ++ if (data == SeeqPHYID0) ++ np->PHYType = SeeqPHY; ++ else if (data == AhdocPHYID0) ++ np->PHYType = AhdocPHY; ++ else if (data == MarvellPHYID0) ++ np->PHYType = MarvellPHY; ++ else if (data == MysonPHYID0) ++ np->PHYType = Myson981; ++ else if (data == LevelOnePHYID0) ++ np->PHYType = LevelOnePHY; ++ else ++ np->PHYType = OtherPHY; ++ } ++ } ++ } ++ ++ np->mii_cnt = phy_idx; ++ if (phy_idx == 0) ++ dev_warn(&pdev->dev, ++ "MII PHY not found -- this device may " ++ "not operate correctly.\n"); ++ } else { ++ np->phys[0] = 32; ++/* 89/6/23 add, (begin) */ ++ /* get phy type */ ++ if (ioread32(ioaddr + PHYIDENTIFIER) == MysonPHYID) ++ np->PHYType = MysonPHY; ++ else ++ np->PHYType = OtherPHY; ++ } ++ np->mii.phy_id = np->phys[0]; ++ ++ if (dev->mem_start) ++ option = dev->mem_start; ++ ++ /* The lower four bits are the media type. */ ++ if (option > 0) { ++ if (option & 0x200) ++ np->mii.full_duplex = 1; ++ np->default_port = option & 15; ++ } ++ ++ if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) ++ np->mii.full_duplex = full_duplex[card_idx]; ++ ++ if (np->mii.full_duplex) { ++ dev_info(&pdev->dev, "Media type forced to Full Duplex.\n"); ++/* 89/6/13 add, (begin) */ ++// if (np->PHYType==MarvellPHY) ++ if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) { ++ unsigned int data; ++ ++ data = mdio_read(dev, np->phys[0], 9); ++ data = (data & 0xfcff) | 0x0200; ++ mdio_write(dev, np->phys[0], 9, data); ++ } ++/* 89/6/13 add, (end) */ ++ if (np->flags == HAS_MII_XCVR) ++ mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL); ++ else ++ iowrite32(ADVERTISE_FULL, ioaddr + ANARANLPAR); ++ np->mii.force_media = 1; ++ } ++ ++ dev->netdev_ops = &netdev_ops; ++ dev->ethtool_ops = &netdev_ethtool_ops; ++ dev->watchdog_timeo = TX_TIMEOUT; ++ ++ err = register_netdev(dev); ++ if (err) ++ goto err_out_free_tx; ++ ++ printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", ++ dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr, ++ dev->dev_addr, irq); ++ ++ return 0; ++ ++err_out_free_tx: ++ dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring, ++ np->tx_ring_dma); ++err_out_free_rx: ++ dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring, ++ np->rx_ring_dma); ++err_out_free_dev: ++ free_netdev(dev); ++err_out_unmap: ++ pci_iounmap(pdev, ioaddr); ++err_out_res: ++ pci_release_regions(pdev); ++ return err; ++} ++ ++ ++static void fealnx_remove_one(struct pci_dev *pdev) ++{ ++ struct net_device *dev = pci_get_drvdata(pdev); ++ ++ if (dev) { ++ struct netdev_private *np = netdev_priv(dev); ++ ++ dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring, ++ np->tx_ring_dma); ++ dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring, ++ np->rx_ring_dma); ++ unregister_netdev(dev); ++ pci_iounmap(pdev, np->mem); ++ free_netdev(dev); ++ pci_release_regions(pdev); ++ } else ++ printk(KERN_ERR "fealnx: remove for unknown device\n"); ++} ++ ++ ++static ulong m80x_send_cmd_to_phy(void __iomem *miiport, int opcode, int phyad, int regad) ++{ ++ ulong miir; ++ int i; ++ unsigned int mask, data; ++ ++ /* enable MII output */ ++ miir = (ulong) ioread32(miiport); ++ miir &= 0xfffffff0; ++ ++ miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO; ++ ++ /* send 32 1's preamble */ ++ for (i = 0; i < 32; i++) { ++ /* low MDC; MDO is already high (miir) */ ++ miir &= ~MASK_MIIR_MII_MDC; ++ iowrite32(miir, miiport); ++ ++ /* high MDC */ ++ miir |= MASK_MIIR_MII_MDC; ++ iowrite32(miir, miiport); ++ } ++ ++ /* calculate ST+OP+PHYAD+REGAD+TA */ ++ data = opcode | (phyad << 7) | (regad << 2); ++ ++ /* sent out */ ++ mask = 0x8000; ++ while (mask) { ++ /* low MDC, prepare MDO */ ++ miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); ++ if (mask & data) ++ miir |= MASK_MIIR_MII_MDO; ++ ++ iowrite32(miir, miiport); ++ /* high MDC */ ++ miir |= MASK_MIIR_MII_MDC; ++ iowrite32(miir, miiport); ++ udelay(30); ++ ++ /* next */ ++ mask >>= 1; ++ if (mask == 0x2 && opcode == OP_READ) ++ miir &= ~MASK_MIIR_MII_WRITE; ++ } ++ return miir; ++} ++ ++ ++static int mdio_read(struct net_device *dev, int phyad, int regad) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *miiport = np->mem + MANAGEMENT; ++ ulong miir; ++ unsigned int mask, data; ++ ++ miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad); ++ ++ /* read data */ ++ mask = 0x8000; ++ data = 0; ++ while (mask) { ++ /* low MDC */ ++ miir &= ~MASK_MIIR_MII_MDC; ++ iowrite32(miir, miiport); ++ ++ /* read MDI */ ++ miir = ioread32(miiport); ++ if (miir & MASK_MIIR_MII_MDI) ++ data |= mask; ++ ++ /* high MDC, and wait */ ++ miir |= MASK_MIIR_MII_MDC; ++ iowrite32(miir, miiport); ++ udelay(30); ++ ++ /* next */ ++ mask >>= 1; ++ } ++ ++ /* low MDC */ ++ miir &= ~MASK_MIIR_MII_MDC; ++ iowrite32(miir, miiport); ++ ++ return data & 0xffff; ++} ++ ++ ++static void mdio_write(struct net_device *dev, int phyad, int regad, int data) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *miiport = np->mem + MANAGEMENT; ++ ulong miir; ++ unsigned int mask; ++ ++ miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad); ++ ++ /* write data */ ++ mask = 0x8000; ++ while (mask) { ++ /* low MDC, prepare MDO */ ++ miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); ++ if (mask & data) ++ miir |= MASK_MIIR_MII_MDO; ++ iowrite32(miir, miiport); ++ ++ /* high MDC */ ++ miir |= MASK_MIIR_MII_MDC; ++ iowrite32(miir, miiport); ++ ++ /* next */ ++ mask >>= 1; ++ } ++ ++ /* low MDC */ ++ miir &= ~MASK_MIIR_MII_MDC; ++ iowrite32(miir, miiport); ++} ++ ++ ++static int netdev_open(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ const int irq = np->pci_dev->irq; ++ int rc, i; ++ ++ iowrite32(0x00000001, ioaddr + BCR); /* Reset */ ++ ++ rc = request_irq(irq, intr_handler, IRQF_SHARED, dev->name, dev); ++ if (rc) ++ return -EAGAIN; ++ ++ for (i = 0; i < 3; i++) ++ iowrite16(((const unsigned short *)dev->dev_addr)[i], ++ ioaddr + PAR0 + i*2); ++ ++ init_ring(dev); ++ ++ iowrite32(np->rx_ring_dma, ioaddr + RXLBA); ++ iowrite32(np->tx_ring_dma, ioaddr + TXLBA); ++ ++ /* Initialize other registers. */ ++ /* Configure the PCI bus bursts and FIFO thresholds. ++ 486: Set 8 longword burst. ++ 586: no burst limit. ++ Burst length 5:3 ++ 0 0 0 1 ++ 0 0 1 4 ++ 0 1 0 8 ++ 0 1 1 16 ++ 1 0 0 32 ++ 1 0 1 64 ++ 1 1 0 128 ++ 1 1 1 256 ++ Wait the specified 50 PCI cycles after a reset by initializing ++ Tx and Rx queues and the address filter list. ++ FIXME (Ueimor): optimistic for alpha + posted writes ? */ ++ ++ np->bcrvalue = 0x10; /* little-endian, 8 burst length */ ++#ifdef __BIG_ENDIAN ++ np->bcrvalue |= 0x04; /* big-endian */ ++#endif ++ ++#if defined(__i386__) && !defined(MODULE) && !defined(CONFIG_UML) ++ if (boot_cpu_data.x86 <= 4) ++ np->crvalue = 0xa00; ++ else ++#endif ++ np->crvalue = 0xe00; /* rx 128 burst length */ ++ ++ ++// 89/12/29 add, ++// 90/1/16 modify, ++// np->imrvalue=FBE|TUNF|CNTOVF|RBU|TI|RI; ++ np->imrvalue = TUNF | CNTOVF | RBU | TI | RI; ++ if (np->pci_dev->device == 0x891) { ++ np->bcrvalue |= 0x200; /* set PROG bit */ ++ np->crvalue |= CR_W_ENH; /* set enhanced bit */ ++ np->imrvalue |= ETI; ++ } ++ iowrite32(np->bcrvalue, ioaddr + BCR); ++ ++ if (dev->if_port == 0) ++ dev->if_port = np->default_port; ++ ++ iowrite32(0, ioaddr + RXPDR); ++// 89/9/1 modify, ++// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */ ++ np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */ ++ np->mii.full_duplex = np->mii.force_media; ++ getlinkstatus(dev); ++ if (np->linkok) ++ getlinktype(dev); ++ __set_rx_mode(dev); ++ ++ netif_start_queue(dev); ++ ++ /* Clear and Enable interrupts by setting the interrupt mask. */ ++ iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); ++ iowrite32(np->imrvalue, ioaddr + IMR); ++ ++ if (debug) ++ printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); ++ ++ /* Set the timer to check for link beat. */ ++ timer_setup(&np->timer, netdev_timer, 0); ++ np->timer.expires = RUN_AT(3 * HZ); ++ ++ /* timer handler */ ++ add_timer(&np->timer); ++ ++ timer_setup(&np->reset_timer, reset_timer, 0); ++ np->reset_timer_armed = 0; ++ return rc; ++} ++ ++ ++static void getlinkstatus(struct net_device *dev) ++/* function: Routine will read MII Status Register to get link status. */ ++/* input : dev... pointer to the adapter block. */ ++/* output : none. */ ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ unsigned int i, DelayTime = 0x1000; ++ ++ np->linkok = 0; ++ ++ if (np->PHYType == MysonPHY) { ++ for (i = 0; i < DelayTime; ++i) { ++ if (ioread32(np->mem + BMCRSR) & LinkIsUp2) { ++ np->linkok = 1; ++ return; ++ } ++ udelay(100); ++ } ++ } else { ++ for (i = 0; i < DelayTime; ++i) { ++ if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) { ++ np->linkok = 1; ++ return; ++ } ++ udelay(100); ++ } ++ } ++} ++ ++ ++static void getlinktype(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ ++ if (np->PHYType == MysonPHY) { /* 3-in-1 case */ ++ if (ioread32(np->mem + TCRRCR) & CR_R_FD) ++ np->duplexmode = 2; /* full duplex */ ++ else ++ np->duplexmode = 1; /* half duplex */ ++ if (ioread32(np->mem + TCRRCR) & CR_R_PS10) ++ np->line_speed = 1; /* 10M */ ++ else ++ np->line_speed = 2; /* 100M */ ++ } else { ++ if (np->PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */ ++ unsigned int data; ++ ++ data = mdio_read(dev, np->phys[0], MIIRegister18); ++ if (data & SPD_DET_100) ++ np->line_speed = 2; /* 100M */ ++ else ++ np->line_speed = 1; /* 10M */ ++ if (data & DPLX_DET_FULL) ++ np->duplexmode = 2; /* full duplex mode */ ++ else ++ np->duplexmode = 1; /* half duplex mode */ ++ } else if (np->PHYType == AhdocPHY) { ++ unsigned int data; ++ ++ data = mdio_read(dev, np->phys[0], DiagnosticReg); ++ if (data & Speed_100) ++ np->line_speed = 2; /* 100M */ ++ else ++ np->line_speed = 1; /* 10M */ ++ if (data & DPLX_FULL) ++ np->duplexmode = 2; /* full duplex mode */ ++ else ++ np->duplexmode = 1; /* half duplex mode */ ++ } ++/* 89/6/13 add, (begin) */ ++ else if (np->PHYType == MarvellPHY) { ++ unsigned int data; ++ ++ data = mdio_read(dev, np->phys[0], SpecificReg); ++ if (data & Full_Duplex) ++ np->duplexmode = 2; /* full duplex mode */ ++ else ++ np->duplexmode = 1; /* half duplex mode */ ++ data &= SpeedMask; ++ if (data == Speed_1000M) ++ np->line_speed = 3; /* 1000M */ ++ else if (data == Speed_100M) ++ np->line_speed = 2; /* 100M */ ++ else ++ np->line_speed = 1; /* 10M */ ++ } ++/* 89/6/13 add, (end) */ ++/* 89/7/27 add, (begin) */ ++ else if (np->PHYType == Myson981) { ++ unsigned int data; ++ ++ data = mdio_read(dev, np->phys[0], StatusRegister); ++ ++ if (data & SPEED100) ++ np->line_speed = 2; ++ else ++ np->line_speed = 1; ++ ++ if (data & FULLMODE) ++ np->duplexmode = 2; ++ else ++ np->duplexmode = 1; ++ } ++/* 89/7/27 add, (end) */ ++/* 89/12/29 add */ ++ else if (np->PHYType == LevelOnePHY) { ++ unsigned int data; ++ ++ data = mdio_read(dev, np->phys[0], SpecificReg); ++ if (data & LXT1000_Full) ++ np->duplexmode = 2; /* full duplex mode */ ++ else ++ np->duplexmode = 1; /* half duplex mode */ ++ data &= SpeedMask; ++ if (data == LXT1000_1000M) ++ np->line_speed = 3; /* 1000M */ ++ else if (data == LXT1000_100M) ++ np->line_speed = 2; /* 100M */ ++ else ++ np->line_speed = 1; /* 10M */ ++ } ++ np->crvalue &= (~CR_W_PS10) & (~CR_W_FD) & (~CR_W_PS1000); ++ if (np->line_speed == 1) ++ np->crvalue |= CR_W_PS10; ++ else if (np->line_speed == 3) ++ np->crvalue |= CR_W_PS1000; ++ if (np->duplexmode == 2) ++ np->crvalue |= CR_W_FD; ++ } ++} ++ ++ ++/* Take lock before calling this */ ++static void allocate_rx_buffers(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ ++ /* allocate skb for rx buffers */ ++ while (np->really_rx_count != RX_RING_SIZE) { ++ struct sk_buff *skb; ++ ++ skb = netdev_alloc_skb(dev, np->rx_buf_sz); ++ if (skb == NULL) ++ break; /* Better luck next round. */ ++ ++ while (np->lack_rxbuf->skbuff) ++ np->lack_rxbuf = np->lack_rxbuf->next_desc_logical; ++ ++ np->lack_rxbuf->skbuff = skb; ++ np->lack_rxbuf->buffer = dma_map_single(&np->pci_dev->dev, ++ skb->data, ++ np->rx_buf_sz, ++ DMA_FROM_DEVICE); ++ np->lack_rxbuf->status = RXOWN; ++ ++np->really_rx_count; ++ } ++} ++ ++ ++static void netdev_timer(struct timer_list *t) ++{ ++ struct netdev_private *np = from_timer(np, t, timer); ++ struct net_device *dev = np->mii.dev; ++ void __iomem *ioaddr = np->mem; ++ int old_crvalue = np->crvalue; ++ unsigned int old_linkok = np->linkok; ++ unsigned long flags; ++ ++ if (debug) ++ printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " ++ "config %8.8x.\n", dev->name, ioread32(ioaddr + ISR), ++ ioread32(ioaddr + TCRRCR)); ++ ++ spin_lock_irqsave(&np->lock, flags); ++ ++ if (np->flags == HAS_MII_XCVR) { ++ getlinkstatus(dev); ++ if ((old_linkok == 0) && (np->linkok == 1)) { /* we need to detect the media type again */ ++ getlinktype(dev); ++ if (np->crvalue != old_crvalue) { ++ stop_nic_rxtx(ioaddr, np->crvalue); ++ iowrite32(np->crvalue, ioaddr + TCRRCR); ++ } ++ } ++ } ++ ++ allocate_rx_buffers(dev); ++ ++ spin_unlock_irqrestore(&np->lock, flags); ++ ++ np->timer.expires = RUN_AT(10 * HZ); ++ add_timer(&np->timer); ++} ++ ++ ++/* Take lock before calling */ ++/* Reset chip and disable rx, tx and interrupts */ ++static void reset_and_disable_rxtx(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ int delay=51; ++ ++ /* Reset the chip's Tx and Rx processes. */ ++ stop_nic_rxtx(ioaddr, 0); ++ ++ /* Disable interrupts by clearing the interrupt mask. */ ++ iowrite32(0, ioaddr + IMR); ++ ++ /* Reset the chip to erase previous misconfiguration. */ ++ iowrite32(0x00000001, ioaddr + BCR); ++ ++ /* Ueimor: wait for 50 PCI cycles (and flush posted writes btw). ++ We surely wait too long (address+data phase). Who cares? */ ++ while (--delay) { ++ ioread32(ioaddr + BCR); ++ rmb(); ++ } ++} ++ ++ ++/* Take lock before calling */ ++/* Restore chip after reset */ ++static void enable_rxtx(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ ++ reset_rx_descriptors(dev); ++ ++ iowrite32(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring), ++ ioaddr + TXLBA); ++ iowrite32(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), ++ ioaddr + RXLBA); ++ ++ iowrite32(np->bcrvalue, ioaddr + BCR); ++ ++ iowrite32(0, ioaddr + RXPDR); ++ __set_rx_mode(dev); /* changes np->crvalue, writes it into TCRRCR */ ++ ++ /* Clear and Enable interrupts by setting the interrupt mask. */ ++ iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); ++ iowrite32(np->imrvalue, ioaddr + IMR); ++ ++ iowrite32(0, ioaddr + TXPDR); ++} ++ ++ ++static void reset_timer(struct timer_list *t) ++{ ++ struct netdev_private *np = from_timer(np, t, reset_timer); ++ struct net_device *dev = np->mii.dev; ++ unsigned long flags; ++ ++ printk(KERN_WARNING "%s: resetting tx and rx machinery\n", dev->name); ++ ++ spin_lock_irqsave(&np->lock, flags); ++ np->crvalue = np->crvalue_sv; ++ np->imrvalue = np->imrvalue_sv; ++ ++ reset_and_disable_rxtx(dev); ++ /* works for me without this: ++ reset_tx_descriptors(dev); */ ++ enable_rxtx(dev); ++ netif_start_queue(dev); /* FIXME: or netif_wake_queue(dev); ? */ ++ ++ np->reset_timer_armed = 0; ++ ++ spin_unlock_irqrestore(&np->lock, flags); ++} ++ ++ ++static void fealnx_tx_timeout(struct net_device *dev, unsigned int txqueue) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ unsigned long flags; ++ int i; ++ ++ printk(KERN_WARNING ++ "%s: Transmit timed out, status %8.8x, resetting...\n", ++ dev->name, ioread32(ioaddr + ISR)); ++ ++ { ++ printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); ++ for (i = 0; i < RX_RING_SIZE; i++) ++ printk(KERN_CONT " %8.8x", ++ (unsigned int) np->rx_ring[i].status); ++ printk(KERN_CONT "\n"); ++ printk(KERN_DEBUG " Tx ring %p: ", np->tx_ring); ++ for (i = 0; i < TX_RING_SIZE; i++) ++ printk(KERN_CONT " %4.4x", np->tx_ring[i].status); ++ printk(KERN_CONT "\n"); ++ } ++ ++ spin_lock_irqsave(&np->lock, flags); ++ ++ reset_and_disable_rxtx(dev); ++ reset_tx_descriptors(dev); ++ enable_rxtx(dev); ++ ++ spin_unlock_irqrestore(&np->lock, flags); ++ ++ netif_trans_update(dev); /* prevent tx timeout */ ++ dev->stats.tx_errors++; ++ netif_wake_queue(dev); /* or .._start_.. ?? */ ++} ++ ++ ++/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ ++static void init_ring(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ int i; ++ ++ /* initialize rx variables */ ++ np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); ++ np->cur_rx = &np->rx_ring[0]; ++ np->lack_rxbuf = np->rx_ring; ++ np->really_rx_count = 0; ++ ++ /* initial rx descriptors. */ ++ for (i = 0; i < RX_RING_SIZE; i++) { ++ np->rx_ring[i].status = 0; ++ np->rx_ring[i].control = np->rx_buf_sz << RBSShift; ++ np->rx_ring[i].next_desc = np->rx_ring_dma + ++ (i + 1)*sizeof(struct fealnx_desc); ++ np->rx_ring[i].next_desc_logical = &np->rx_ring[i + 1]; ++ np->rx_ring[i].skbuff = NULL; ++ } ++ ++ /* for the last rx descriptor */ ++ np->rx_ring[i - 1].next_desc = np->rx_ring_dma; ++ np->rx_ring[i - 1].next_desc_logical = np->rx_ring; ++ ++ /* allocate skb for rx buffers */ ++ for (i = 0; i < RX_RING_SIZE; i++) { ++ struct sk_buff *skb = netdev_alloc_skb(dev, np->rx_buf_sz); ++ ++ if (skb == NULL) { ++ np->lack_rxbuf = &np->rx_ring[i]; ++ break; ++ } ++ ++ ++np->really_rx_count; ++ np->rx_ring[i].skbuff = skb; ++ np->rx_ring[i].buffer = dma_map_single(&np->pci_dev->dev, ++ skb->data, ++ np->rx_buf_sz, ++ DMA_FROM_DEVICE); ++ np->rx_ring[i].status = RXOWN; ++ np->rx_ring[i].control |= RXIC; ++ } ++ ++ /* initialize tx variables */ ++ np->cur_tx = &np->tx_ring[0]; ++ np->cur_tx_copy = &np->tx_ring[0]; ++ np->really_tx_count = 0; ++ np->free_tx_count = TX_RING_SIZE; ++ ++ for (i = 0; i < TX_RING_SIZE; i++) { ++ np->tx_ring[i].status = 0; ++ /* do we need np->tx_ring[i].control = XXX; ?? */ ++ np->tx_ring[i].next_desc = np->tx_ring_dma + ++ (i + 1)*sizeof(struct fealnx_desc); ++ np->tx_ring[i].next_desc_logical = &np->tx_ring[i + 1]; ++ np->tx_ring[i].skbuff = NULL; ++ } ++ ++ /* for the last tx descriptor */ ++ np->tx_ring[i - 1].next_desc = np->tx_ring_dma; ++ np->tx_ring[i - 1].next_desc_logical = &np->tx_ring[0]; ++} ++ ++ ++static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&np->lock, flags); ++ ++ np->cur_tx_copy->skbuff = skb; ++ ++#define one_buffer ++#define BPT 1022 ++#if defined(one_buffer) ++ np->cur_tx_copy->buffer = dma_map_single(&np->pci_dev->dev, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ np->cur_tx_copy->control = TXIC | TXLD | TXFD | CRCEnable | PADEnable; ++ np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ ++ np->cur_tx_copy->control |= (skb->len << TBSShift); /* buffer size */ ++// 89/12/29 add, ++ if (np->pci_dev->device == 0x891) ++ np->cur_tx_copy->control |= ETIControl | RetryTxLC; ++ np->cur_tx_copy->status = TXOWN; ++ np->cur_tx_copy = np->cur_tx_copy->next_desc_logical; ++ --np->free_tx_count; ++#elif defined(two_buffer) ++ if (skb->len > BPT) { ++ struct fealnx_desc *next; ++ ++ /* for the first descriptor */ ++ np->cur_tx_copy->buffer = dma_map_single(&np->pci_dev->dev, ++ skb->data, BPT, ++ DMA_TO_DEVICE); ++ np->cur_tx_copy->control = TXIC | TXFD | CRCEnable | PADEnable; ++ np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ ++ np->cur_tx_copy->control |= (BPT << TBSShift); /* buffer size */ ++ ++ /* for the last descriptor */ ++ next = np->cur_tx_copy->next_desc_logical; ++ next->skbuff = skb; ++ next->control = TXIC | TXLD | CRCEnable | PADEnable; ++ next->control |= (skb->len << PKTSShift); /* pkt size */ ++ next->control |= ((skb->len - BPT) << TBSShift); /* buf size */ ++// 89/12/29 add, ++ if (np->pci_dev->device == 0x891) ++ np->cur_tx_copy->control |= ETIControl | RetryTxLC; ++ next->buffer = dma_map_single(&ep->pci_dev->dev, ++ skb->data + BPT, skb->len - BPT, ++ DMA_TO_DEVICE); ++ ++ next->status = TXOWN; ++ np->cur_tx_copy->status = TXOWN; ++ ++ np->cur_tx_copy = next->next_desc_logical; ++ np->free_tx_count -= 2; ++ } else { ++ np->cur_tx_copy->buffer = dma_map_single(&np->pci_dev->dev, ++ skb->data, skb->len, ++ DMA_TO_DEVICE); ++ np->cur_tx_copy->control = TXIC | TXLD | TXFD | CRCEnable | PADEnable; ++ np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ ++ np->cur_tx_copy->control |= (skb->len << TBSShift); /* buffer size */ ++// 89/12/29 add, ++ if (np->pci_dev->device == 0x891) ++ np->cur_tx_copy->control |= ETIControl | RetryTxLC; ++ np->cur_tx_copy->status = TXOWN; ++ np->cur_tx_copy = np->cur_tx_copy->next_desc_logical; ++ --np->free_tx_count; ++ } ++#endif ++ ++ if (np->free_tx_count < 2) ++ netif_stop_queue(dev); ++ ++np->really_tx_count; ++ iowrite32(0, np->mem + TXPDR); ++ ++ spin_unlock_irqrestore(&np->lock, flags); ++ return NETDEV_TX_OK; ++} ++ ++ ++/* Take lock before calling */ ++/* Chip probably hosed tx ring. Clean up. */ ++static void reset_tx_descriptors(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ struct fealnx_desc *cur; ++ int i; ++ ++ /* initialize tx variables */ ++ np->cur_tx = &np->tx_ring[0]; ++ np->cur_tx_copy = &np->tx_ring[0]; ++ np->really_tx_count = 0; ++ np->free_tx_count = TX_RING_SIZE; ++ ++ for (i = 0; i < TX_RING_SIZE; i++) { ++ cur = &np->tx_ring[i]; ++ if (cur->skbuff) { ++ dma_unmap_single(&np->pci_dev->dev, cur->buffer, ++ cur->skbuff->len, DMA_TO_DEVICE); ++ dev_kfree_skb_any(cur->skbuff); ++ cur->skbuff = NULL; ++ } ++ cur->status = 0; ++ cur->control = 0; /* needed? */ ++ /* probably not needed. We do it for purely paranoid reasons */ ++ cur->next_desc = np->tx_ring_dma + ++ (i + 1)*sizeof(struct fealnx_desc); ++ cur->next_desc_logical = &np->tx_ring[i + 1]; ++ } ++ /* for the last tx descriptor */ ++ np->tx_ring[TX_RING_SIZE - 1].next_desc = np->tx_ring_dma; ++ np->tx_ring[TX_RING_SIZE - 1].next_desc_logical = &np->tx_ring[0]; ++} ++ ++ ++/* Take lock and stop rx before calling this */ ++static void reset_rx_descriptors(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ struct fealnx_desc *cur = np->cur_rx; ++ int i; ++ ++ allocate_rx_buffers(dev); ++ ++ for (i = 0; i < RX_RING_SIZE; i++) { ++ if (cur->skbuff) ++ cur->status = RXOWN; ++ cur = cur->next_desc_logical; ++ } ++ ++ iowrite32(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), ++ np->mem + RXLBA); ++} ++ ++ ++/* The interrupt handler does all of the Rx thread work and cleans up ++ after the Tx thread. */ ++static irqreturn_t intr_handler(int irq, void *dev_instance) ++{ ++ struct net_device *dev = (struct net_device *) dev_instance; ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ long boguscnt = max_interrupt_work; ++ unsigned int num_tx = 0; ++ int handled = 0; ++ ++ spin_lock(&np->lock); ++ ++ iowrite32(0, ioaddr + IMR); ++ ++ do { ++ u32 intr_status = ioread32(ioaddr + ISR); ++ ++ /* Acknowledge all of the current interrupt sources ASAP. */ ++ iowrite32(intr_status, ioaddr + ISR); ++ ++ if (debug) ++ printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name, ++ intr_status); ++ ++ if (!(intr_status & np->imrvalue)) ++ break; ++ ++ handled = 1; ++ ++// 90/1/16 delete, ++// ++// if (intr_status & FBE) ++// { /* fatal error */ ++// stop_nic_tx(ioaddr, 0); ++// stop_nic_rx(ioaddr, 0); ++// break; ++// }; ++ ++ if (intr_status & TUNF) ++ iowrite32(0, ioaddr + TXPDR); ++ ++ if (intr_status & CNTOVF) { ++ /* missed pkts */ ++ dev->stats.rx_missed_errors += ++ ioread32(ioaddr + TALLY) & 0x7fff; ++ ++ /* crc error */ ++ dev->stats.rx_crc_errors += ++ (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; ++ } ++ ++ if (intr_status & (RI | RBU)) { ++ if (intr_status & RI) ++ netdev_rx(dev); ++ else { ++ stop_nic_rx(ioaddr, np->crvalue); ++ reset_rx_descriptors(dev); ++ iowrite32(np->crvalue, ioaddr + TCRRCR); ++ } ++ } ++ ++ while (np->really_tx_count) { ++ long tx_status = np->cur_tx->status; ++ long tx_control = np->cur_tx->control; ++ ++ if (!(tx_control & TXLD)) { /* this pkt is combined by two tx descriptors */ ++ struct fealnx_desc *next; ++ ++ next = np->cur_tx->next_desc_logical; ++ tx_status = next->status; ++ tx_control = next->control; ++ } ++ ++ if (tx_status & TXOWN) ++ break; ++ ++ if (!(np->crvalue & CR_W_ENH)) { ++ if (tx_status & (CSL | LC | EC | UDF | HF)) { ++ dev->stats.tx_errors++; ++ if (tx_status & EC) ++ dev->stats.tx_aborted_errors++; ++ if (tx_status & CSL) ++ dev->stats.tx_carrier_errors++; ++ if (tx_status & LC) ++ dev->stats.tx_window_errors++; ++ if (tx_status & UDF) ++ dev->stats.tx_fifo_errors++; ++ if ((tx_status & HF) && np->mii.full_duplex == 0) ++ dev->stats.tx_heartbeat_errors++; ++ ++ } else { ++ dev->stats.tx_bytes += ++ ((tx_control & PKTSMask) >> PKTSShift); ++ ++ dev->stats.collisions += ++ ((tx_status & NCRMask) >> NCRShift); ++ dev->stats.tx_packets++; ++ } ++ } else { ++ dev->stats.tx_bytes += ++ ((tx_control & PKTSMask) >> PKTSShift); ++ dev->stats.tx_packets++; ++ } ++ ++ /* Free the original skb. */ ++ dma_unmap_single(&np->pci_dev->dev, ++ np->cur_tx->buffer, ++ np->cur_tx->skbuff->len, ++ DMA_TO_DEVICE); ++ dev_consume_skb_irq(np->cur_tx->skbuff); ++ np->cur_tx->skbuff = NULL; ++ --np->really_tx_count; ++ if (np->cur_tx->control & TXLD) { ++ np->cur_tx = np->cur_tx->next_desc_logical; ++ ++np->free_tx_count; ++ } else { ++ np->cur_tx = np->cur_tx->next_desc_logical; ++ np->cur_tx = np->cur_tx->next_desc_logical; ++ np->free_tx_count += 2; ++ } ++ num_tx++; ++ } /* end of for loop */ ++ ++ if (num_tx && np->free_tx_count >= 2) ++ netif_wake_queue(dev); ++ ++ /* read transmit status for enhanced mode only */ ++ if (np->crvalue & CR_W_ENH) { ++ long data; ++ ++ data = ioread32(ioaddr + TSR); ++ dev->stats.tx_errors += (data & 0xff000000) >> 24; ++ dev->stats.tx_aborted_errors += ++ (data & 0xff000000) >> 24; ++ dev->stats.tx_window_errors += ++ (data & 0x00ff0000) >> 16; ++ dev->stats.collisions += (data & 0x0000ffff); ++ } ++ ++ if (--boguscnt < 0) { ++ printk(KERN_WARNING "%s: Too much work at interrupt, " ++ "status=0x%4.4x.\n", dev->name, intr_status); ++ if (!np->reset_timer_armed) { ++ np->reset_timer_armed = 1; ++ np->reset_timer.expires = RUN_AT(HZ/2); ++ add_timer(&np->reset_timer); ++ stop_nic_rxtx(ioaddr, 0); ++ netif_stop_queue(dev); ++ /* or netif_tx_disable(dev); ?? */ ++ /* Prevent other paths from enabling tx,rx,intrs */ ++ np->crvalue_sv = np->crvalue; ++ np->imrvalue_sv = np->imrvalue; ++ np->crvalue &= ~(CR_W_TXEN | CR_W_RXEN); /* or simply = 0? */ ++ np->imrvalue = 0; ++ } ++ ++ break; ++ } ++ } while (1); ++ ++ /* read the tally counters */ ++ /* missed pkts */ ++ dev->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff; ++ ++ /* crc error */ ++ dev->stats.rx_crc_errors += ++ (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; ++ ++ if (debug) ++ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", ++ dev->name, ioread32(ioaddr + ISR)); ++ ++ iowrite32(np->imrvalue, ioaddr + IMR); ++ ++ spin_unlock(&np->lock); ++ ++ return IRQ_RETVAL(handled); ++} ++ ++ ++/* This routine is logically part of the interrupt handler, but separated ++ for clarity and better register allocation. */ ++static int netdev_rx(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ ++ /* If EOP is set on the next entry, it's a new packet. Send it up. */ ++ while (!(np->cur_rx->status & RXOWN) && np->cur_rx->skbuff) { ++ s32 rx_status = np->cur_rx->status; ++ ++ if (np->really_rx_count == 0) ++ break; ++ ++ if (debug) ++ printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", rx_status); ++ ++ if ((!((rx_status & RXFSD) && (rx_status & RXLSD))) || ++ (rx_status & ErrorSummary)) { ++ if (rx_status & ErrorSummary) { /* there was a fatal error */ ++ if (debug) ++ printk(KERN_DEBUG ++ "%s: Receive error, Rx status %8.8x.\n", ++ dev->name, rx_status); ++ ++ dev->stats.rx_errors++; /* end of a packet. */ ++ if (rx_status & (LONGPKT | RUNTPKT)) ++ dev->stats.rx_length_errors++; ++ if (rx_status & RXER) ++ dev->stats.rx_frame_errors++; ++ if (rx_status & CRC) ++ dev->stats.rx_crc_errors++; ++ } else { ++ int need_to_reset = 0; ++ int desno = 0; ++ ++ if (rx_status & RXFSD) { /* this pkt is too long, over one rx buffer */ ++ struct fealnx_desc *cur; ++ ++ /* check this packet is received completely? */ ++ cur = np->cur_rx; ++ while (desno <= np->really_rx_count) { ++ ++desno; ++ if ((!(cur->status & RXOWN)) && ++ (cur->status & RXLSD)) ++ break; ++ /* goto next rx descriptor */ ++ cur = cur->next_desc_logical; ++ } ++ if (desno > np->really_rx_count) ++ need_to_reset = 1; ++ } else /* RXLSD did not find, something error */ ++ need_to_reset = 1; ++ ++ if (need_to_reset == 0) { ++ int i; ++ ++ dev->stats.rx_length_errors++; ++ ++ /* free all rx descriptors related this long pkt */ ++ for (i = 0; i < desno; ++i) { ++ if (!np->cur_rx->skbuff) { ++ printk(KERN_DEBUG ++ "%s: I'm scared\n", dev->name); ++ break; ++ } ++ np->cur_rx->status = RXOWN; ++ np->cur_rx = np->cur_rx->next_desc_logical; ++ } ++ continue; ++ } else { /* rx error, need to reset this chip */ ++ stop_nic_rx(ioaddr, np->crvalue); ++ reset_rx_descriptors(dev); ++ iowrite32(np->crvalue, ioaddr + TCRRCR); ++ } ++ break; /* exit the while loop */ ++ } ++ } else { /* this received pkt is ok */ ++ ++ struct sk_buff *skb; ++ /* Omit the four octet CRC from the length. */ ++ short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4; ++ ++#ifndef final_version ++ if (debug) ++ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" ++ " status %x.\n", pkt_len, rx_status); ++#endif ++ ++ /* Check if the packet is long enough to accept without copying ++ to a minimally-sized skbuff. */ ++ if (pkt_len < rx_copybreak && ++ (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { ++ skb_reserve(skb, 2); /* 16 byte align the IP header */ ++ dma_sync_single_for_cpu(&np->pci_dev->dev, ++ np->cur_rx->buffer, ++ np->rx_buf_sz, ++ DMA_FROM_DEVICE); ++ /* Call copy + cksum if available. */ ++ ++#if ! defined(__alpha__) ++ skb_copy_to_linear_data(skb, ++ np->cur_rx->skbuff->data, pkt_len); ++ skb_put(skb, pkt_len); ++#else ++ skb_put_data(skb, np->cur_rx->skbuff->data, ++ pkt_len); ++#endif ++ dma_sync_single_for_device(&np->pci_dev->dev, ++ np->cur_rx->buffer, ++ np->rx_buf_sz, ++ DMA_FROM_DEVICE); ++ } else { ++ dma_unmap_single(&np->pci_dev->dev, ++ np->cur_rx->buffer, ++ np->rx_buf_sz, ++ DMA_FROM_DEVICE); ++ skb_put(skb = np->cur_rx->skbuff, pkt_len); ++ np->cur_rx->skbuff = NULL; ++ --np->really_rx_count; ++ } ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ dev->stats.rx_packets++; ++ dev->stats.rx_bytes += pkt_len; ++ } ++ ++ np->cur_rx = np->cur_rx->next_desc_logical; ++ } /* end of while loop */ ++ ++ /* allocate skb for rx buffers */ ++ allocate_rx_buffers(dev); ++ ++ return 0; ++} ++ ++ ++static struct net_device_stats *get_stats(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ ++ /* The chip only need report frame silently dropped. */ ++ if (netif_running(dev)) { ++ dev->stats.rx_missed_errors += ++ ioread32(ioaddr + TALLY) & 0x7fff; ++ dev->stats.rx_crc_errors += ++ (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; ++ } ++ ++ return &dev->stats; ++} ++ ++ ++/* for dev->set_multicast_list */ ++static void set_rx_mode(struct net_device *dev) ++{ ++ spinlock_t *lp = &((struct netdev_private *)netdev_priv(dev))->lock; ++ unsigned long flags; ++ spin_lock_irqsave(lp, flags); ++ __set_rx_mode(dev); ++ spin_unlock_irqrestore(lp, flags); ++} ++ ++ ++/* Take lock before calling */ ++static void __set_rx_mode(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ u32 mc_filter[2]; /* Multicast hash filter */ ++ u32 rx_mode; ++ ++ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ ++ memset(mc_filter, 0xff, sizeof(mc_filter)); ++ rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM; ++ } else if ((netdev_mc_count(dev) > multicast_filter_limit) || ++ (dev->flags & IFF_ALLMULTI)) { ++ /* Too many to match, or accept all multicasts. */ ++ memset(mc_filter, 0xff, sizeof(mc_filter)); ++ rx_mode = CR_W_AB | CR_W_AM; ++ } else { ++ struct netdev_hw_addr *ha; ++ ++ memset(mc_filter, 0, sizeof(mc_filter)); ++ netdev_for_each_mc_addr(ha, dev) { ++ unsigned int bit; ++ bit = (ether_crc(ETH_ALEN, ha->addr) >> 26) ^ 0x3F; ++ mc_filter[bit >> 5] |= (1 << bit); ++ } ++ rx_mode = CR_W_AB | CR_W_AM; ++ } ++ ++ stop_nic_rxtx(ioaddr, np->crvalue); ++ ++ iowrite32(mc_filter[0], ioaddr + MAR0); ++ iowrite32(mc_filter[1], ioaddr + MAR1); ++ np->crvalue &= ~CR_W_RXMODEMASK; ++ np->crvalue |= rx_mode; ++ iowrite32(np->crvalue, ioaddr + TCRRCR); ++} ++ ++static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ ++ strscpy(info->driver, DRV_NAME, sizeof(info->driver)); ++ strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); ++} ++ ++static int netdev_get_link_ksettings(struct net_device *dev, ++ struct ethtool_link_ksettings *cmd) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ ++ spin_lock_irq(&np->lock); ++ mii_ethtool_get_link_ksettings(&np->mii, cmd); ++ spin_unlock_irq(&np->lock); ++ ++ return 0; ++} ++ ++static int netdev_set_link_ksettings(struct net_device *dev, ++ const struct ethtool_link_ksettings *cmd) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ int rc; ++ ++ spin_lock_irq(&np->lock); ++ rc = mii_ethtool_set_link_ksettings(&np->mii, cmd); ++ spin_unlock_irq(&np->lock); ++ ++ return rc; ++} ++ ++static int netdev_nway_reset(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ return mii_nway_restart(&np->mii); ++} ++ ++static u32 netdev_get_link(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ return mii_link_ok(&np->mii); ++} ++ ++static u32 netdev_get_msglevel(struct net_device *dev) ++{ ++ return debug; ++} ++ ++static void netdev_set_msglevel(struct net_device *dev, u32 value) ++{ ++ debug = value; ++} ++ ++static const struct ethtool_ops netdev_ethtool_ops = { ++ .get_drvinfo = netdev_get_drvinfo, ++ .nway_reset = netdev_nway_reset, ++ .get_link = netdev_get_link, ++ .get_msglevel = netdev_get_msglevel, ++ .set_msglevel = netdev_set_msglevel, ++ .get_link_ksettings = netdev_get_link_ksettings, ++ .set_link_ksettings = netdev_set_link_ksettings, ++}; ++ ++static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ int rc; ++ ++ if (!netif_running(dev)) ++ return -EINVAL; ++ ++ spin_lock_irq(&np->lock); ++ rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL); ++ spin_unlock_irq(&np->lock); ++ ++ return rc; ++} ++ ++ ++static int netdev_close(struct net_device *dev) ++{ ++ struct netdev_private *np = netdev_priv(dev); ++ void __iomem *ioaddr = np->mem; ++ int i; ++ ++ netif_stop_queue(dev); ++ ++ /* Disable interrupts by clearing the interrupt mask. */ ++ iowrite32(0x0000, ioaddr + IMR); ++ ++ /* Stop the chip's Tx and Rx processes. */ ++ stop_nic_rxtx(ioaddr, 0); ++ ++ del_timer_sync(&np->timer); ++ del_timer_sync(&np->reset_timer); ++ ++ free_irq(np->pci_dev->irq, dev); ++ ++ /* Free all the skbuffs in the Rx queue. */ ++ for (i = 0; i < RX_RING_SIZE; i++) { ++ struct sk_buff *skb = np->rx_ring[i].skbuff; ++ ++ np->rx_ring[i].status = 0; ++ if (skb) { ++ dma_unmap_single(&np->pci_dev->dev, ++ np->rx_ring[i].buffer, np->rx_buf_sz, ++ DMA_FROM_DEVICE); ++ dev_kfree_skb(skb); ++ np->rx_ring[i].skbuff = NULL; ++ } ++ } ++ ++ for (i = 0; i < TX_RING_SIZE; i++) { ++ struct sk_buff *skb = np->tx_ring[i].skbuff; ++ ++ if (skb) { ++ dma_unmap_single(&np->pci_dev->dev, ++ np->tx_ring[i].buffer, skb->len, ++ DMA_TO_DEVICE); ++ dev_kfree_skb(skb); ++ np->tx_ring[i].skbuff = NULL; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct pci_device_id fealnx_pci_tbl[] = { ++ {0x1516, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x1516, 0x0803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, ++ {0x1516, 0x0891, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, ++ {} /* terminate list */ ++}; ++MODULE_DEVICE_TABLE(pci, fealnx_pci_tbl); ++ ++ ++static struct pci_driver fealnx_driver = { ++ .name = "fealnx", ++ .id_table = fealnx_pci_tbl, ++ .probe = fealnx_init_one, ++ .remove = fealnx_remove_one, ++}; ++ ++module_pci_driver(fealnx_driver); diff --git a/queue-6.2/net-tls-avoid-hanging-tasks-on-the-tx_lock.patch b/queue-6.2/net-tls-avoid-hanging-tasks-on-the-tx_lock.patch new file mode 100644 index 00000000000..bdf3fce9a0d --- /dev/null +++ b/queue-6.2/net-tls-avoid-hanging-tasks-on-the-tx_lock.patch @@ -0,0 +1,78 @@ +From f3221361dc85d4de22586ce8441ec2c67b454f5d Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Tue, 28 Feb 2023 16:28:57 -0800 +Subject: net: tls: avoid hanging tasks on the tx_lock + +From: Jakub Kicinski + +commit f3221361dc85d4de22586ce8441ec2c67b454f5d upstream. + +syzbot sent a hung task report and Eric explains that adversarial +receiver may keep RWIN at 0 for a long time, so we are not guaranteed +to make forward progress. Thread which took tx_lock and went to sleep +may not release tx_lock for hours. Use interruptible sleep where +possible and reschedule the work if it can't take the lock. + +Testing: existing selftest passes + +Reported-by: syzbot+9c0268252b8ef967c62e@syzkaller.appspotmail.com +Fixes: 79ffe6087e91 ("net/tls: add a TX lock") +Link: https://lore.kernel.org/all/000000000000e412e905f5b46201@google.com/ +Cc: stable@vger.kernel.org # wait 4 weeks +Reviewed-by: Eric Dumazet +Link: https://lore.kernel.org/r/20230301002857.2101894-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/tls/tls_sw.c | 26 +++++++++++++++++++------- + 1 file changed, 19 insertions(+), 7 deletions(-) + +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -941,7 +941,9 @@ int tls_sw_sendmsg(struct sock *sk, stru + MSG_CMSG_COMPAT)) + return -EOPNOTSUPP; + +- mutex_lock(&tls_ctx->tx_lock); ++ ret = mutex_lock_interruptible(&tls_ctx->tx_lock); ++ if (ret) ++ return ret; + lock_sock(sk); + + if (unlikely(msg->msg_controllen)) { +@@ -1275,7 +1277,9 @@ int tls_sw_sendpage(struct sock *sk, str + MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY)) + return -EOPNOTSUPP; + +- mutex_lock(&tls_ctx->tx_lock); ++ ret = mutex_lock_interruptible(&tls_ctx->tx_lock); ++ if (ret) ++ return ret; + lock_sock(sk); + ret = tls_sw_do_sendpage(sk, page, offset, size, flags); + release_sock(sk); +@@ -2416,11 +2420,19 @@ static void tx_work_handler(struct work_ + + if (!test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) + return; +- mutex_lock(&tls_ctx->tx_lock); +- lock_sock(sk); +- tls_tx_records(sk, -1); +- release_sock(sk); +- mutex_unlock(&tls_ctx->tx_lock); ++ ++ if (mutex_trylock(&tls_ctx->tx_lock)) { ++ lock_sock(sk); ++ tls_tx_records(sk, -1); ++ release_sock(sk); ++ mutex_unlock(&tls_ctx->tx_lock); ++ } else if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) { ++ /* Someone is holding the tx_lock, they will likely run Tx ++ * and cancel the work on their way out of the lock section. ++ * Schedule a long delay just in case. ++ */ ++ schedule_delayed_work(&ctx->tx_work.work, msecs_to_jiffies(10)); ++ } + } + + static bool tls_is_tx_ready(struct tls_sw_context_tx *ctx) diff --git a/queue-6.2/series b/queue-6.2/series index 4b0a89a4219..48c9b74fbe2 100644 --- a/queue-6.2/series +++ b/queue-6.2/series @@ -185,3 +185,17 @@ phy-rockchip-typec-fix-unsigned-comparison-with-less.patch rdma-cma-distinguish-between-sockaddr_in-and-sockadd.patch soundwire-cadence-remove-wasted-space-in-response_bu.patch soundwire-cadence-drain-the-rx-fifo-after-an-io-time.patch +eth-fealnx-bring-back-this-old-driver.patch +net-tls-avoid-hanging-tasks-on-the-tx_lock.patch +x86-resctl-fix-scheduler-confusion-with-current.patch +vdpa-ifcvf-decouple-hw-features-manipulators-from-the-adapter.patch +vdpa-ifcvf-decouple-config-space-ops-from-the-adapter.patch +vdpa-ifcvf-alloc-the-mgmt_dev-before-the-adapter.patch +vdpa-ifcvf-decouple-vq-irq-releasers-from-the-adapter.patch +vdpa-ifcvf-decouple-config-irq-releaser-from-the-adapter.patch +vdpa-ifcvf-decouple-vq-irq-requester-from-the-adapter.patch +vdpa-ifcvf-decouple-config-dev-irq-requester-and-vectors-allocator-from-the-adapter.patch +vdpa-ifcvf-ifcvf_request_irq-works-on-ifcvf_hw.patch +vdpa-ifcvf-manage-ifcvf_hw-in-the-mgmt_dev.patch +vdpa-ifcvf-allocate-the-adapter-in-dev_add.patch +drm-display-dp_mst-add-drm_atomic_get_old_mst_topology_state.patch diff --git a/queue-6.2/vdpa-ifcvf-alloc-the-mgmt_dev-before-the-adapter.patch b/queue-6.2/vdpa-ifcvf-alloc-the-mgmt_dev-before-the-adapter.patch new file mode 100644 index 00000000000..016c6723fdb --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-alloc-the-mgmt_dev-before-the-adapter.patch @@ -0,0 +1,92 @@ +From 66e3970b16d1e960afbece65739a3628273633f1 Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:15 +0800 +Subject: vDPA/ifcvf: alloc the mgmt_dev before the adapter + +From: Zhu Lingshan + +commit 66e3970b16d1e960afbece65739a3628273633f1 upstream. + +This commit reverses the order of allocating the +management device and the adapter. So that it would +be possible to move the allocation of the adapter +to dev_add(). + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-4-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_main.c | 31 ++++++++++++++----------------- + 1 file changed, 14 insertions(+), 17 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -831,22 +831,30 @@ static int ifcvf_probe(struct pci_dev *p + } + + pci_set_master(pdev); ++ ifcvf_mgmt_dev = kzalloc(sizeof(struct ifcvf_vdpa_mgmt_dev), GFP_KERNEL); ++ if (!ifcvf_mgmt_dev) { ++ IFCVF_ERR(pdev, "Failed to alloc memory for the vDPA management device\n"); ++ return -ENOMEM; ++ } + + adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, + dev, &ifc_vdpa_ops, 1, 1, NULL, false); + if (IS_ERR(adapter)) { + IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); +- return PTR_ERR(adapter); ++ ret = PTR_ERR(adapter); ++ goto err; + } + ++ adapter->pdev = pdev; ++ adapter->vdpa.dma_dev = &pdev->dev; ++ adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev; ++ ifcvf_mgmt_dev->adapter = adapter; ++ + vf = &adapter->vf; + vf->dev_type = get_dev_type(pdev); + vf->base = pcim_iomap_table(pdev); + vf->pdev = pdev; + +- adapter->pdev = pdev; +- adapter->vdpa.dma_dev = &pdev->dev; +- + ret = ifcvf_init_hw(vf, pdev); + if (ret) { + IFCVF_ERR(pdev, "Failed to init IFCVF hw\n"); +@@ -859,16 +867,6 @@ static int ifcvf_probe(struct pci_dev *p + vf->hw_features = ifcvf_get_hw_features(vf); + vf->config_size = ifcvf_get_config_size(vf); + +- ifcvf_mgmt_dev = kzalloc(sizeof(struct ifcvf_vdpa_mgmt_dev), GFP_KERNEL); +- if (!ifcvf_mgmt_dev) { +- IFCVF_ERR(pdev, "Failed to alloc memory for the vDPA management device\n"); +- return -ENOMEM; +- } +- +- ifcvf_mgmt_dev->mdev.ops = &ifcvf_vdpa_mgmt_dev_ops; +- ifcvf_mgmt_dev->mdev.device = dev; +- ifcvf_mgmt_dev->adapter = adapter; +- + dev_type = get_dev_type(pdev); + switch (dev_type) { + case VIRTIO_ID_NET: +@@ -883,12 +881,11 @@ static int ifcvf_probe(struct pci_dev *p + goto err; + } + ++ ifcvf_mgmt_dev->mdev.ops = &ifcvf_vdpa_mgmt_dev_ops; ++ ifcvf_mgmt_dev->mdev.device = dev; + ifcvf_mgmt_dev->mdev.max_supported_vqs = vf->nr_vring; + ifcvf_mgmt_dev->mdev.supported_features = vf->hw_features; + +- adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev; +- +- + ret = vdpa_mgmtdev_register(&ifcvf_mgmt_dev->mdev); + if (ret) { + IFCVF_ERR(pdev, diff --git a/queue-6.2/vdpa-ifcvf-allocate-the-adapter-in-dev_add.patch b/queue-6.2/vdpa-ifcvf-allocate-the-adapter-in-dev_add.patch new file mode 100644 index 00000000000..b3820580535 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-allocate-the-adapter-in-dev_add.patch @@ -0,0 +1,93 @@ +From 93139037b582134deb1ed894bbc4bc1d34ff35e7 Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:22 +0800 +Subject: vDPA/ifcvf: allocate the adapter in dev_add() + +From: Zhu Lingshan + +commit 93139037b582134deb1ed894bbc4bc1d34ff35e7 upstream. + +The adapter is the container of the vdpa_device, +this commits allocate the adapter in dev_add() +rather than in probe(). So that the vdpa_device() +could be re-created when the userspace creates +the vdpa device, and free-ed in dev_del() + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-11-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_main.c | 34 +++++++++++++--------------------- + 1 file changed, 13 insertions(+), 21 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -746,12 +746,20 @@ static int ifcvf_vdpa_dev_add(struct vdp + int ret; + + ifcvf_mgmt_dev = container_of(mdev, struct ifcvf_vdpa_mgmt_dev, mdev); +- if (!ifcvf_mgmt_dev->adapter) +- return -EOPNOTSUPP; ++ vf = &ifcvf_mgmt_dev->vf; ++ pdev = vf->pdev; ++ adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, ++ &pdev->dev, &ifc_vdpa_ops, 1, 1, NULL, false); ++ if (IS_ERR(adapter)) { ++ IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); ++ return PTR_ERR(adapter); ++ } + +- adapter = ifcvf_mgmt_dev->adapter; +- vf = adapter->vf; +- pdev = adapter->pdev; ++ ifcvf_mgmt_dev->adapter = adapter; ++ adapter->pdev = pdev; ++ adapter->vdpa.dma_dev = &pdev->dev; ++ adapter->vdpa.mdev = mdev; ++ adapter->vf = vf; + vdpa_dev = &adapter->vdpa; + + if (name) +@@ -769,7 +777,6 @@ static int ifcvf_vdpa_dev_add(struct vdp + return 0; + } + +- + static void ifcvf_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev) + { + struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev; +@@ -788,7 +795,6 @@ static int ifcvf_probe(struct pci_dev *p + { + struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev; + struct device *dev = &pdev->dev; +- struct ifcvf_adapter *adapter; + struct ifcvf_hw *vf; + u32 dev_type; + int ret, i; +@@ -825,24 +831,10 @@ static int ifcvf_probe(struct pci_dev *p + return -ENOMEM; + } + +- adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, +- dev, &ifc_vdpa_ops, 1, 1, NULL, false); +- if (IS_ERR(adapter)) { +- IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); +- ret = PTR_ERR(adapter); +- goto err; +- } +- +- adapter->pdev = pdev; +- adapter->vdpa.dma_dev = &pdev->dev; +- adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev; +- ifcvf_mgmt_dev->adapter = adapter; +- + vf = &ifcvf_mgmt_dev->vf; + vf->dev_type = get_dev_type(pdev); + vf->base = pcim_iomap_table(pdev); + vf->pdev = pdev; +- adapter->vf = vf; + + ret = ifcvf_init_hw(vf, pdev); + if (ret) { diff --git a/queue-6.2/vdpa-ifcvf-decouple-config-dev-irq-requester-and-vectors-allocator-from-the-adapter.patch b/queue-6.2/vdpa-ifcvf-decouple-config-dev-irq-requester-and-vectors-allocator-from-the-adapter.patch new file mode 100644 index 00000000000..47670299d80 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-decouple-config-dev-irq-requester-and-vectors-allocator-from-the-adapter.patch @@ -0,0 +1,91 @@ +From a70d833e696e538a0feff5e539086c74a90ddf90 Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:19 +0800 +Subject: vDPA/ifcvf: decouple config/dev IRQ requester and vectors allocator from the adapter + +From: Zhu Lingshan + +commit a70d833e696e538a0feff5e539086c74a90ddf90 upstream. + +This commit decouples the config irq requester, the device +shared irq requester and the MSI vectors allocator from +the adapter. So they can be safely invoked since probe +before the adapter is allocated. + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-8-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_main.c | 21 +++++++++------------ + 1 file changed, 9 insertions(+), 12 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -132,10 +132,9 @@ static void ifcvf_free_irq(struct ifcvf_ + * It returns the number of allocated vectors, negative + * return value when fails. + */ +-static int ifcvf_alloc_vectors(struct ifcvf_adapter *adapter) ++static int ifcvf_alloc_vectors(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + int max_intr, ret; + + /* all queues and config interrupt */ +@@ -222,10 +221,9 @@ err: + return -EFAULT; + } + +-static int ifcvf_request_dev_irq(struct ifcvf_adapter *adapter) ++static int ifcvf_request_dev_irq(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + int i, vector, ret, irq; + + vector = 0; +@@ -276,10 +274,9 @@ static int ifcvf_request_vq_irq(struct i + return ret; + } + +-static int ifcvf_request_config_irq(struct ifcvf_adapter *adapter) ++static int ifcvf_request_config_irq(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + int config_vector, ret; + + if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) +@@ -322,7 +319,7 @@ static int ifcvf_request_irq(struct ifcv + struct ifcvf_hw *vf = &adapter->vf; + int nvectors, ret, max_intr; + +- nvectors = ifcvf_alloc_vectors(adapter); ++ nvectors = ifcvf_alloc_vectors(vf); + if (nvectors <= 0) + return -EFAULT; + +@@ -333,7 +330,7 @@ static int ifcvf_request_irq(struct ifcv + + if (nvectors == 1) { + vf->msix_vector_status = MSIX_VECTOR_DEV_SHARED; +- ret = ifcvf_request_dev_irq(adapter); ++ ret = ifcvf_request_dev_irq(vf); + + return ret; + } +@@ -342,7 +339,7 @@ static int ifcvf_request_irq(struct ifcv + if (ret) + return ret; + +- ret = ifcvf_request_config_irq(adapter); ++ ret = ifcvf_request_config_irq(vf); + + if (ret) + return ret; diff --git a/queue-6.2/vdpa-ifcvf-decouple-config-irq-releaser-from-the-adapter.patch b/queue-6.2/vdpa-ifcvf-decouple-config-irq-releaser-from-the-adapter.patch new file mode 100644 index 00000000000..70c1dddfb92 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-decouple-config-irq-releaser-from-the-adapter.patch @@ -0,0 +1,99 @@ +From 23dac55cec3afdbc1b4eaed1c79f2cee00477f8b Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:17 +0800 +Subject: vDPA/ifcvf: decouple config IRQ releaser from the adapter + +From: Zhu Lingshan + +commit 23dac55cec3afdbc1b4eaed1c79f2cee00477f8b upstream. + +This commit decouples config IRQ releaser from the adapter, +so that it could be invoked once probe or in err handlers. +ifcvf_free_irq() works on ifcvf_hw in this commit + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-6-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_main.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -101,10 +101,9 @@ static void ifcvf_free_vq_irq(struct ifc + ifcvf_free_vqs_reused_irq(vf); + } + +-static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter) ++static void ifcvf_free_config_irq(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + + if (vf->config_irq == -EINVAL) + return; +@@ -119,13 +118,12 @@ static void ifcvf_free_config_irq(struct + } + } + +-static void ifcvf_free_irq(struct ifcvf_adapter *adapter) ++static void ifcvf_free_irq(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + + ifcvf_free_vq_irq(vf); +- ifcvf_free_config_irq(adapter); ++ ifcvf_free_config_irq(vf); + ifcvf_free_irq_vectors(pdev); + } + +@@ -187,7 +185,7 @@ static int ifcvf_request_per_vq_irq(stru + + return 0; + err: +- ifcvf_free_irq(adapter); ++ ifcvf_free_irq(vf); + + return -EFAULT; + } +@@ -221,7 +219,7 @@ static int ifcvf_request_vqs_reused_irq( + + return 0; + err: +- ifcvf_free_irq(adapter); ++ ifcvf_free_irq(vf); + + return -EFAULT; + } +@@ -262,7 +260,7 @@ static int ifcvf_request_dev_irq(struct + + return 0; + err: +- ifcvf_free_irq(adapter); ++ ifcvf_free_irq(vf); + + return -EFAULT; + +@@ -317,7 +315,7 @@ static int ifcvf_request_config_irq(stru + + return 0; + err: +- ifcvf_free_irq(adapter); ++ ifcvf_free_irq(vf); + + return -EFAULT; + } +@@ -508,7 +506,7 @@ static int ifcvf_vdpa_reset(struct vdpa_ + + if (status_old & VIRTIO_CONFIG_S_DRIVER_OK) { + ifcvf_stop_datapath(adapter); +- ifcvf_free_irq(adapter); ++ ifcvf_free_irq(vf); + } + + ifcvf_reset_vring(adapter); diff --git a/queue-6.2/vdpa-ifcvf-decouple-config-space-ops-from-the-adapter.patch b/queue-6.2/vdpa-ifcvf-decouple-config-space-ops-from-the-adapter.patch new file mode 100644 index 00000000000..19ac5c0e0f5 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-decouple-config-space-ops-from-the-adapter.patch @@ -0,0 +1,97 @@ +From af8eb69a62b73a2ce5f91575453534ac07f06eb4 Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:14 +0800 +Subject: vDPA/ifcvf: decouple config space ops from the adapter + +From: Zhu Lingshan + +commit af8eb69a62b73a2ce5f91575453534ac07f06eb4 upstream. + +This commit decopules the config space ops from the +adapter layer, so these functions can be invoked +once the device is probed. + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-3-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_base.c | 21 +++++---------------- + 1 file changed, 5 insertions(+), 16 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_base.c ++++ b/drivers/vdpa/ifcvf/ifcvf_base.c +@@ -10,11 +10,6 @@ + + #include "ifcvf_base.h" + +-struct ifcvf_adapter *vf_to_adapter(struct ifcvf_hw *hw) +-{ +- return container_of(hw, struct ifcvf_adapter, vf); +-} +- + u16 ifcvf_set_vq_vector(struct ifcvf_hw *hw, u16 qid, int vector) + { + struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; +@@ -37,8 +32,6 @@ u16 ifcvf_set_config_vector(struct ifcvf + static void __iomem *get_cap_addr(struct ifcvf_hw *hw, + struct virtio_pci_cap *cap) + { +- struct ifcvf_adapter *ifcvf; +- struct pci_dev *pdev; + u32 length, offset; + u8 bar; + +@@ -46,17 +39,14 @@ static void __iomem *get_cap_addr(struct + offset = le32_to_cpu(cap->offset); + bar = cap->bar; + +- ifcvf= vf_to_adapter(hw); +- pdev = ifcvf->pdev; +- + if (bar >= IFCVF_PCI_MAX_RESOURCE) { +- IFCVF_DBG(pdev, ++ IFCVF_DBG(hw->pdev, + "Invalid bar number %u to get capabilities\n", bar); + return NULL; + } + +- if (offset + length > pci_resource_len(pdev, bar)) { +- IFCVF_DBG(pdev, ++ if (offset + length > pci_resource_len(hw->pdev, bar)) { ++ IFCVF_DBG(hw->pdev, + "offset(%u) + len(%u) overflows bar%u's capability\n", + offset, length, bar); + return NULL; +@@ -92,6 +82,7 @@ int ifcvf_init_hw(struct ifcvf_hw *hw, s + IFCVF_ERR(pdev, "Failed to read PCI capability list\n"); + return -EIO; + } ++ hw->pdev = pdev; + + while (pos) { + ret = ifcvf_read_config_range(pdev, (u32 *)&cap, +@@ -230,13 +221,11 @@ int ifcvf_verify_min_features(struct ifc + + u32 ifcvf_get_config_size(struct ifcvf_hw *hw) + { +- struct ifcvf_adapter *adapter; + u32 net_config_size = sizeof(struct virtio_net_config); + u32 blk_config_size = sizeof(struct virtio_blk_config); + u32 cap_size = hw->cap_dev_config_size; + u32 config_size; + +- adapter = vf_to_adapter(hw); + /* If the onboard device config space size is greater than + * the size of struct virtio_net/blk_config, only the spec + * implementing contents size is returned, this is very +@@ -251,7 +240,7 @@ u32 ifcvf_get_config_size(struct ifcvf_h + break; + default: + config_size = 0; +- IFCVF_ERR(adapter->pdev, "VIRTIO ID %u not supported\n", hw->dev_type); ++ IFCVF_ERR(hw->pdev, "VIRTIO ID %u not supported\n", hw->dev_type); + } + + return config_size; diff --git a/queue-6.2/vdpa-ifcvf-decouple-hw-features-manipulators-from-the-adapter.patch b/queue-6.2/vdpa-ifcvf-decouple-hw-features-manipulators-from-the-adapter.patch new file mode 100644 index 00000000000..b1ab3cdccc2 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-decouple-hw-features-manipulators-from-the-adapter.patch @@ -0,0 +1,76 @@ +From d59f633dd05940739b5f46f5d4403cafb91d2742 Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:13 +0800 +Subject: vDPA/ifcvf: decouple hw features manipulators from the adapter + +From: Zhu Lingshan + +commit d59f633dd05940739b5f46f5d4403cafb91d2742 upstream. + +This commit gets rid of ifcvf_adapter in hw features related +functions in ifcvf_base. Then these functions are more rubust +and de-coupling from the ifcvf_adapter layer. So these +functions could be invoded once the device is probed, even +before the adapter is allocaed. + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-2-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_base.c | 9 ++------- + drivers/vdpa/ifcvf/ifcvf_base.h | 1 + + drivers/vdpa/ifcvf/ifcvf_main.c | 1 + + 3 files changed, 4 insertions(+), 7 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_base.c ++++ b/drivers/vdpa/ifcvf/ifcvf_base.c +@@ -220,10 +220,8 @@ u64 ifcvf_get_features(struct ifcvf_hw * + + int ifcvf_verify_min_features(struct ifcvf_hw *hw, u64 features) + { +- struct ifcvf_adapter *ifcvf = vf_to_adapter(hw); +- + if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)) && features) { +- IFCVF_ERR(ifcvf->pdev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n"); ++ IFCVF_ERR(hw->pdev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n"); + return -EINVAL; + } + +@@ -301,14 +299,11 @@ static void ifcvf_set_features(struct if + + static int ifcvf_config_features(struct ifcvf_hw *hw) + { +- struct ifcvf_adapter *ifcvf; +- +- ifcvf = vf_to_adapter(hw); + ifcvf_set_features(hw, hw->req_features); + ifcvf_add_status(hw, VIRTIO_CONFIG_S_FEATURES_OK); + + if (!(ifcvf_get_status(hw) & VIRTIO_CONFIG_S_FEATURES_OK)) { +- IFCVF_ERR(ifcvf->pdev, "Failed to set FEATURES_OK status\n"); ++ IFCVF_ERR(hw->pdev, "Failed to set FEATURES_OK status\n"); + return -EIO; + } + +--- a/drivers/vdpa/ifcvf/ifcvf_base.h ++++ b/drivers/vdpa/ifcvf/ifcvf_base.h +@@ -89,6 +89,7 @@ struct ifcvf_hw { + u16 nr_vring; + /* VIRTIO_PCI_CAP_DEVICE_CFG size */ + u32 cap_dev_config_size; ++ struct pci_dev *pdev; + }; + + struct ifcvf_adapter { +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -842,6 +842,7 @@ static int ifcvf_probe(struct pci_dev *p + vf = &adapter->vf; + vf->dev_type = get_dev_type(pdev); + vf->base = pcim_iomap_table(pdev); ++ vf->pdev = pdev; + + adapter->pdev = pdev; + adapter->vdpa.dma_dev = &pdev->dev; diff --git a/queue-6.2/vdpa-ifcvf-decouple-vq-irq-releasers-from-the-adapter.patch b/queue-6.2/vdpa-ifcvf-decouple-vq-irq-releasers-from-the-adapter.patch new file mode 100644 index 00000000000..e9d81c77521 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-decouple-vq-irq-releasers-from-the-adapter.patch @@ -0,0 +1,79 @@ +From 004cbcabab46d9346e2524c4eedd71ea57fe4f3c Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:16 +0800 +Subject: vDPA/ifcvf: decouple vq IRQ releasers from the adapter + +From: Zhu Lingshan + +commit 004cbcabab46d9346e2524c4eedd71ea57fe4f3c upstream. + +This commit decouples the IRQ releasers from the +adapter, so that these functions could be +safely invoked once probe + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-5-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_main.c | 21 +++++++++------------ + 1 file changed, 9 insertions(+), 12 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -69,10 +69,9 @@ static void ifcvf_free_irq_vectors(void + pci_free_irq_vectors(data); + } + +-static void ifcvf_free_per_vq_irq(struct ifcvf_adapter *adapter) ++static void ifcvf_free_per_vq_irq(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + int i; + + for (i = 0; i < vf->nr_vring; i++) { +@@ -83,10 +82,9 @@ static void ifcvf_free_per_vq_irq(struct + } + } + +-static void ifcvf_free_vqs_reused_irq(struct ifcvf_adapter *adapter) ++static void ifcvf_free_vqs_reused_irq(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + + if (vf->vqs_reused_irq != -EINVAL) { + devm_free_irq(&pdev->dev, vf->vqs_reused_irq, vf); +@@ -95,14 +93,12 @@ static void ifcvf_free_vqs_reused_irq(st + + } + +-static void ifcvf_free_vq_irq(struct ifcvf_adapter *adapter) ++static void ifcvf_free_vq_irq(struct ifcvf_hw *vf) + { +- struct ifcvf_hw *vf = &adapter->vf; +- + if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) +- ifcvf_free_per_vq_irq(adapter); ++ ifcvf_free_per_vq_irq(vf); + else +- ifcvf_free_vqs_reused_irq(adapter); ++ ifcvf_free_vqs_reused_irq(vf); + } + + static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter) +@@ -126,8 +122,9 @@ static void ifcvf_free_config_irq(struct + static void ifcvf_free_irq(struct ifcvf_adapter *adapter) + { + struct pci_dev *pdev = adapter->pdev; ++ struct ifcvf_hw *vf = &adapter->vf; + +- ifcvf_free_vq_irq(adapter); ++ ifcvf_free_vq_irq(vf); + ifcvf_free_config_irq(adapter); + ifcvf_free_irq_vectors(pdev); + } diff --git a/queue-6.2/vdpa-ifcvf-decouple-vq-irq-requester-from-the-adapter.patch b/queue-6.2/vdpa-ifcvf-decouple-vq-irq-requester-from-the-adapter.patch new file mode 100644 index 00000000000..fbd6a3a2e22 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-decouple-vq-irq-requester-from-the-adapter.patch @@ -0,0 +1,77 @@ +From f9a9ffb2e4dbde81090416fc51662441c2a7b73b Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:18 +0800 +Subject: vDPA/ifcvf: decouple vq irq requester from the adapter + +From: Zhu Lingshan + +commit f9a9ffb2e4dbde81090416fc51662441c2a7b73b upstream. + +This commit decouples the vq irq requester from the adapter, +so that these functions can be invoked since probe. + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-7-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_main.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -155,10 +155,9 @@ static int ifcvf_alloc_vectors(struct if + return ret; + } + +-static int ifcvf_request_per_vq_irq(struct ifcvf_adapter *adapter) ++static int ifcvf_request_per_vq_irq(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + int i, vector, ret, irq; + + vf->vqs_reused_irq = -EINVAL; +@@ -190,10 +189,9 @@ err: + return -EFAULT; + } + +-static int ifcvf_request_vqs_reused_irq(struct ifcvf_adapter *adapter) ++static int ifcvf_request_vqs_reused_irq(struct ifcvf_hw *vf) + { +- struct pci_dev *pdev = adapter->pdev; +- struct ifcvf_hw *vf = &adapter->vf; ++ struct pci_dev *pdev = vf->pdev; + int i, vector, ret, irq; + + vector = 0; +@@ -266,15 +264,14 @@ err: + + } + +-static int ifcvf_request_vq_irq(struct ifcvf_adapter *adapter) ++static int ifcvf_request_vq_irq(struct ifcvf_hw *vf) + { +- struct ifcvf_hw *vf = &adapter->vf; + int ret; + + if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) +- ret = ifcvf_request_per_vq_irq(adapter); ++ ret = ifcvf_request_per_vq_irq(vf); + else +- ret = ifcvf_request_vqs_reused_irq(adapter); ++ ret = ifcvf_request_vqs_reused_irq(vf); + + return ret; + } +@@ -341,7 +338,7 @@ static int ifcvf_request_irq(struct ifcv + return ret; + } + +- ret = ifcvf_request_vq_irq(adapter); ++ ret = ifcvf_request_vq_irq(vf); + if (ret) + return ret; + diff --git a/queue-6.2/vdpa-ifcvf-ifcvf_request_irq-works-on-ifcvf_hw.patch b/queue-6.2/vdpa-ifcvf-ifcvf_request_irq-works-on-ifcvf_hw.patch new file mode 100644 index 00000000000..dfac8f3bce3 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-ifcvf_request_irq-works-on-ifcvf_hw.patch @@ -0,0 +1,44 @@ +From 7cfd36b7e8be6bdaeb5af0f9729871b732a7a3c8 Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:20 +0800 +Subject: vDPA/ifcvf: ifcvf_request_irq works on ifcvf_hw + +From: Zhu Lingshan + +commit 7cfd36b7e8be6bdaeb5af0f9729871b732a7a3c8 upstream. + +All ifcvf_request_irq's callees are refactored +to work on ifcvf_hw, so it should be decoupled +from the adapter as well + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-9-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_main.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -314,9 +314,8 @@ err: + return -EFAULT; + } + +-static int ifcvf_request_irq(struct ifcvf_adapter *adapter) ++static int ifcvf_request_irq(struct ifcvf_hw *vf) + { +- struct ifcvf_hw *vf = &adapter->vf; + int nvectors, ret, max_intr; + + nvectors = ifcvf_alloc_vectors(vf); +@@ -468,7 +467,7 @@ static void ifcvf_vdpa_set_status(struct + + if ((status & VIRTIO_CONFIG_S_DRIVER_OK) && + !(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) { +- ret = ifcvf_request_irq(adapter); ++ ret = ifcvf_request_irq(vf); + if (ret) { + status = ifcvf_get_status(vf); + status |= VIRTIO_CONFIG_S_FAILED; diff --git a/queue-6.2/vdpa-ifcvf-manage-ifcvf_hw-in-the-mgmt_dev.patch b/queue-6.2/vdpa-ifcvf-manage-ifcvf_hw-in-the-mgmt_dev.patch new file mode 100644 index 00000000000..826a1669251 --- /dev/null +++ b/queue-6.2/vdpa-ifcvf-manage-ifcvf_hw-in-the-mgmt_dev.patch @@ -0,0 +1,85 @@ +From 6a3b2f179b49f2c6452ecc37b4778a43848b454c Mon Sep 17 00:00:00 2001 +From: Zhu Lingshan +Date: Fri, 25 Nov 2022 22:57:21 +0800 +Subject: vDPA/ifcvf: manage ifcvf_hw in the mgmt_dev + +From: Zhu Lingshan + +commit 6a3b2f179b49f2c6452ecc37b4778a43848b454c upstream. + +This commit allocates the hw structure in the +management device structure. So the hardware +can be initialized once the management device +is allocated in probe. + +Signed-off-by: Zhu Lingshan +Cc: stable@vger.kernel.org +Message-Id: <20221125145724.1129962-10-lingshan.zhu@intel.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vdpa/ifcvf/ifcvf_base.h | 5 +++-- + drivers/vdpa/ifcvf/ifcvf_main.c | 7 ++++--- + 2 files changed, 7 insertions(+), 5 deletions(-) + +--- a/drivers/vdpa/ifcvf/ifcvf_base.h ++++ b/drivers/vdpa/ifcvf/ifcvf_base.h +@@ -39,7 +39,7 @@ + #define IFCVF_INFO(pdev, fmt, ...) dev_info(&pdev->dev, fmt, ##__VA_ARGS__) + + #define ifcvf_private_to_vf(adapter) \ +- (&((struct ifcvf_adapter *)adapter)->vf) ++ (((struct ifcvf_adapter *)adapter)->vf) + + /* all vqs and config interrupt has its own vector */ + #define MSIX_VECTOR_PER_VQ_AND_CONFIG 1 +@@ -95,7 +95,7 @@ struct ifcvf_hw { + struct ifcvf_adapter { + struct vdpa_device vdpa; + struct pci_dev *pdev; +- struct ifcvf_hw vf; ++ struct ifcvf_hw *vf; + }; + + struct ifcvf_vring_lm_cfg { +@@ -110,6 +110,7 @@ struct ifcvf_lm_cfg { + + struct ifcvf_vdpa_mgmt_dev { + struct vdpa_mgmt_dev mdev; ++ struct ifcvf_hw vf; + struct ifcvf_adapter *adapter; + struct pci_dev *pdev; + }; +--- a/drivers/vdpa/ifcvf/ifcvf_main.c ++++ b/drivers/vdpa/ifcvf/ifcvf_main.c +@@ -402,7 +402,7 @@ static struct ifcvf_hw *vdpa_to_vf(struc + { + struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev); + +- return &adapter->vf; ++ return adapter->vf; + } + + static u64 ifcvf_vdpa_get_device_features(struct vdpa_device *vdpa_dev) +@@ -750,7 +750,7 @@ static int ifcvf_vdpa_dev_add(struct vdp + return -EOPNOTSUPP; + + adapter = ifcvf_mgmt_dev->adapter; +- vf = &adapter->vf; ++ vf = adapter->vf; + pdev = adapter->pdev; + vdpa_dev = &adapter->vdpa; + +@@ -838,10 +838,11 @@ static int ifcvf_probe(struct pci_dev *p + adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev; + ifcvf_mgmt_dev->adapter = adapter; + +- vf = &adapter->vf; ++ vf = &ifcvf_mgmt_dev->vf; + vf->dev_type = get_dev_type(pdev); + vf->base = pcim_iomap_table(pdev); + vf->pdev = pdev; ++ adapter->vf = vf; + + ret = ifcvf_init_hw(vf, pdev); + if (ret) { diff --git a/queue-6.2/x86-resctl-fix-scheduler-confusion-with-current.patch b/queue-6.2/x86-resctl-fix-scheduler-confusion-with-current.patch new file mode 100644 index 00000000000..d941aff7fa5 --- /dev/null +++ b/queue-6.2/x86-resctl-fix-scheduler-confusion-with-current.patch @@ -0,0 +1,178 @@ +From 7fef099702527c3b2c5234a2ea6a24411485a13a Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Tue, 7 Mar 2023 13:06:29 -0800 +Subject: x86/resctl: fix scheduler confusion with 'current' + +From: Linus Torvalds + +commit 7fef099702527c3b2c5234a2ea6a24411485a13a upstream. + +The implementation of 'current' on x86 is very intentionally special: it +is a very common thing to look up, and it uses 'this_cpu_read_stable()' +to get the current thread pointer efficiently from per-cpu storage. + +And the keyword in there is 'stable': the current thread pointer never +changes as far as a single thread is concerned. Even if when a thread +is preempted, or moved to another CPU, or even across an explicit call +'schedule()' that thread will still have the same value for 'current'. + +It is, after all, the kernel base pointer to thread-local storage. +That's why it's stable to begin with, but it's also why it's important +enough that we have that special 'this_cpu_read_stable()' access for it. + +So this is all done very intentionally to allow the compiler to treat +'current' as a value that never visibly changes, so that the compiler +can do CSE and combine multiple different 'current' accesses into one. + +However, there is obviously one very special situation when the +currently running thread does actually change: inside the scheduler +itself. + +So the scheduler code paths are special, and do not have a 'current' +thread at all. Instead there are _two_ threads: the previous and the +next thread - typically called 'prev' and 'next' (or prev_p/next_p) +internally. + +So this is all actually quite straightforward and simple, and not all +that complicated. + +Except for when you then have special code that is run in scheduler +context, that code then has to be aware that 'current' isn't really a +valid thing. Did you mean 'prev'? Did you mean 'next'? + +In fact, even if then look at the code, and you use 'current' after the +new value has been assigned to the percpu variable, we have explicitly +told the compiler that 'current' is magical and always stable. So the +compiler is quite free to use an older (or newer) value of 'current', +and the actual assignment to the percpu storage is not relevant even if +it might look that way. + +Which is exactly what happened in the resctl code, that blithely used +'current' in '__resctrl_sched_in()' when it really wanted the new +process state (as implied by the name: we're scheduling 'into' that new +resctl state). And clang would end up just using the old thread pointer +value at least in some configurations. + +This could have happened with gcc too, and purely depends on random +compiler details. Clang just seems to have been more aggressive about +moving the read of the per-cpu current_task pointer around. + +The fix is trivial: just make the resctl code adhere to the scheduler +rules of using the prev/next thread pointer explicitly, instead of using +'current' in a situation where it just wasn't valid. + +That same code is then also used outside of the scheduler context (when +a thread resctl state is explicitly changed), and then we will just pass +in 'current' as that pointer, of course. There is no ambiguity in that +case. + +The fix may be trivial, but noticing and figuring out what went wrong +was not. The credit for that goes to Stephane Eranian. + +Reported-by: Stephane Eranian +Link: https://lore.kernel.org/lkml/20230303231133.1486085-1-eranian@google.com/ +Link: https://lore.kernel.org/lkml/alpine.LFD.2.01.0908011214330.3304@localhost.localdomain/ +Reviewed-by: Nick Desaulniers +Tested-by: Tony Luck +Tested-by: Stephane Eranian +Tested-by: Babu Moger +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/resctrl.h | 12 ++++++------ + arch/x86/kernel/cpu/resctrl/rdtgroup.c | 4 ++-- + arch/x86/kernel/process_32.c | 2 +- + arch/x86/kernel/process_64.c | 2 +- + 4 files changed, 10 insertions(+), 10 deletions(-) + +--- a/arch/x86/include/asm/resctrl.h ++++ b/arch/x86/include/asm/resctrl.h +@@ -49,7 +49,7 @@ DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_ + * simple as possible. + * Must be called with preemption disabled. + */ +-static void __resctrl_sched_in(void) ++static inline void __resctrl_sched_in(struct task_struct *tsk) + { + struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state); + u32 closid = state->default_closid; +@@ -61,13 +61,13 @@ static void __resctrl_sched_in(void) + * Else use the closid/rmid assigned to this cpu. + */ + if (static_branch_likely(&rdt_alloc_enable_key)) { +- tmp = READ_ONCE(current->closid); ++ tmp = READ_ONCE(tsk->closid); + if (tmp) + closid = tmp; + } + + if (static_branch_likely(&rdt_mon_enable_key)) { +- tmp = READ_ONCE(current->rmid); ++ tmp = READ_ONCE(tsk->rmid); + if (tmp) + rmid = tmp; + } +@@ -88,17 +88,17 @@ static inline unsigned int resctrl_arch_ + return val * scale; + } + +-static inline void resctrl_sched_in(void) ++static inline void resctrl_sched_in(struct task_struct *tsk) + { + if (static_branch_likely(&rdt_enable_key)) +- __resctrl_sched_in(); ++ __resctrl_sched_in(tsk); + } + + void resctrl_cpu_detect(struct cpuinfo_x86 *c); + + #else + +-static inline void resctrl_sched_in(void) {} ++static inline void resctrl_sched_in(struct task_struct *tsk) {} + static inline void resctrl_cpu_detect(struct cpuinfo_x86 *c) {} + + #endif /* CONFIG_X86_CPU_RESCTRL */ +--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c ++++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c +@@ -314,7 +314,7 @@ static void update_cpu_closid_rmid(void + * executing task might have its own closid selected. Just reuse + * the context switch code. + */ +- resctrl_sched_in(); ++ resctrl_sched_in(current); + } + + /* +@@ -535,7 +535,7 @@ static void _update_task_closid_rmid(voi + * Otherwise, the MSR is updated when the task is scheduled in. + */ + if (task == current) +- resctrl_sched_in(); ++ resctrl_sched_in(task); + } + + static void update_task_closid_rmid(struct task_struct *t) +--- a/arch/x86/kernel/process_32.c ++++ b/arch/x86/kernel/process_32.c +@@ -212,7 +212,7 @@ __switch_to(struct task_struct *prev_p, + switch_fpu_finish(); + + /* Load the Intel cache allocation PQR MSR. */ +- resctrl_sched_in(); ++ resctrl_sched_in(next_p); + + return prev_p; + } +--- a/arch/x86/kernel/process_64.c ++++ b/arch/x86/kernel/process_64.c +@@ -656,7 +656,7 @@ __switch_to(struct task_struct *prev_p, + } + + /* Load the Intel cache allocation PQR MSR. */ +- resctrl_sched_in(); ++ resctrl_sched_in(next_p); + + return prev_p; + }