mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
Merge 5706383b30 ("Merge branch 'mlxsw-Add-support-for-transceiver-modules-reset'") into android-mainline
Steps on the way to 5.16-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ifb072443b5abc0b490407c4475ef822a14f5a7d3
This commit is contained in:
174
Documentation/ABI/testing/sysfs-timecard
Normal file
174
Documentation/ABI/testing/sysfs-timecard
Normal file
@@ -0,0 +1,174 @@
|
||||
What: /sys/class/timecard/
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: This directory contains files and directories
|
||||
providing a standardized interface to the ancillary
|
||||
features of the OpenCompute timecard.
|
||||
|
||||
What: /sys/class/timecard/ocpN/
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: This directory contains the attributes of the Nth timecard
|
||||
registered.
|
||||
|
||||
What: /sys/class/timecard/ocpN/available_clock_sources
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) The list of available time sources that the PHC
|
||||
uses for clock adjustments.
|
||||
|
||||
==== =================================================
|
||||
NONE no adjustments
|
||||
PPS adjustments come from the PPS1 selector (default)
|
||||
TOD adjustments from the GNSS/TOD module
|
||||
IRIG adjustments from external IRIG-B signal
|
||||
DCF adjustments from external DCF signal
|
||||
==== =================================================
|
||||
|
||||
What: /sys/class/timecard/ocpN/available_sma_inputs
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Set of available destinations (sinks) for a SMA
|
||||
input signal.
|
||||
|
||||
===== ================================================
|
||||
10Mhz signal is used as the 10Mhz reference clock
|
||||
PPS1 signal is sent to the PPS1 selector
|
||||
PPS2 signal is sent to the PPS2 selector
|
||||
TS1 signal is sent to timestamper 1
|
||||
TS2 signal is sent to timestamper 2
|
||||
IRIG signal is sent to the IRIG-B module
|
||||
DCF signal is sent to the DCF module
|
||||
===== ================================================
|
||||
|
||||
What: /sys/class/timecard/ocpN/available_sma_outputs
|
||||
Date: May 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Set of available sources for a SMA output signal.
|
||||
|
||||
===== ================================================
|
||||
10Mhz output is from the 10Mhz reference clock
|
||||
PHC output PPS is from the PHC clock
|
||||
MAC output PPS is from the Miniature Atomic Clock
|
||||
GNSS output PPS is from the GNSS module
|
||||
GNSS2 output PPS is from the second GNSS module
|
||||
IRIG output is from the PHC, in IRIG-B format
|
||||
DCF output is from the PHC, in DCF format
|
||||
===== ================================================
|
||||
|
||||
What: /sys/class/timecard/ocpN/clock_source
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RW) Contains the current synchronization source used by
|
||||
the PHC. May be changed by writing one of the listed
|
||||
values from the available_clock_sources attribute set.
|
||||
|
||||
What: /sys/class/timecard/ocpN/gnss_sync
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Indicates whether a valid GNSS signal is received,
|
||||
or when the signal was lost.
|
||||
|
||||
What: /sys/class/timecard/ocpN/i2c
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: This optional attribute links to the associated i2c device.
|
||||
|
||||
What: /sys/class/timecard/ocpN/irig_b_mode
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RW) An integer from 0-7 indicating the timecode format
|
||||
of the IRIG-B output signal: B00<n>
|
||||
|
||||
What: /sys/class/timecard/ocpN/pps
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: This optional attribute links to the associated PPS device.
|
||||
|
||||
What: /sys/class/timecard/ocpN/ptp
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: This attribute links to the associated PTP device.
|
||||
|
||||
What: /sys/class/timecard/ocpN/serialnum
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Provides the serial number of the timecard.
|
||||
|
||||
What: /sys/class/timecard/ocpN/sma1
|
||||
What: /sys/class/timecard/ocpN/sma2
|
||||
What: /sys/class/timecard/ocpN/sma3
|
||||
What: /sys/class/timecard/ocpN/sma4
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RW) These attributes specify the direction of the signal
|
||||
on the associated SMA connectors, and also the signal sink
|
||||
or source.
|
||||
|
||||
The display format of the attribute is a space separated
|
||||
list of signals, prefixed by the input/output direction.
|
||||
|
||||
The signal direction may be changed (if supported) by
|
||||
prefixing the signal list with either "in:" or "out:".
|
||||
If neither prefix is present, then the direction is unchanged.
|
||||
|
||||
The output signal may be changed by writing one of the listed
|
||||
values from the available_sma_outputs attribute set.
|
||||
|
||||
The input destinations may be changed by writing multiple
|
||||
values from the available_sma_inputs attribute set,
|
||||
separated by spaces. If there are duplicated input
|
||||
destinations between connectors, the lowest numbered SMA
|
||||
connector is given priority.
|
||||
|
||||
Note that not all input combinations may make sense.
|
||||
|
||||
The 10Mhz reference clock input is currently only valid
|
||||
on SMA1 and may not be combined with other destination sinks.
|
||||
|
||||
What: /sys/class/timecard/ocpN/ts_window_adjust
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RW) When retrieving the PHC with the PTP SYS_OFFSET_EXTENDED
|
||||
ioctl, a system timestamp is made before and after the PHC
|
||||
time is retrieved. The midpoint between the two system
|
||||
timestamps is usually taken to be the SYS time associated
|
||||
with the PHC time. This estimate may be wrong, as it depends
|
||||
on PCI latencies, and when the PHC time was latched
|
||||
|
||||
The attribute value reduces the end timestamp by the given
|
||||
number of nanoseconds, so the computed midpoint matches the
|
||||
retrieved PHC time.
|
||||
|
||||
The initial value is set based on measured PCI latency and
|
||||
the estimated point where the FPGA latches the PHC time. This
|
||||
value may be changed by writing an unsigned integer.
|
||||
|
||||
What: /sys/class/timecard/ocpN/ttyGNSS
|
||||
What: /sys/class/timecard/ocpN/ttyGNSS2
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: These optional attributes link to the TTY serial ports
|
||||
associated with the GNSS devices.
|
||||
|
||||
What: /sys/class/timecard/ocpN/ttyMAC
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: This optional attribute links to the TTY serial port
|
||||
associated with the Miniature Atomic Clock.
|
||||
|
||||
What: /sys/class/timecard/ocpN/ttyNMEA
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: This optional attribute links to the TTY serial port
|
||||
which outputs the PHC time in NMEA ZDA format.
|
||||
|
||||
What: /sys/class/timecard/ocpN/utc_tai_offset
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RW) The DCF and IRIG output signals are in UTC, while the
|
||||
TimeCard operates on TAI. This attribute allows setting the
|
||||
offset in seconds, which is added to the TAI timebase for
|
||||
these formats.
|
||||
|
||||
The offset may be changed by writing an unsigned integer.
|
||||
69
Documentation/devicetree/bindings/net/lantiq,etop-xway.yaml
Normal file
69
Documentation/devicetree/bindings/net/lantiq,etop-xway.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/lantiq,etop-xway.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Lantiq Xway ETOP Ethernet driver
|
||||
|
||||
maintainers:
|
||||
- John Crispin <john@phrozen.org>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^ethernet@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: lantiq,etop-xway
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: TX interrupt
|
||||
- description: RX interrupt
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
lantiq,tx-burst-length:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
TX programmable burst length.
|
||||
enum: [2, 4, 8]
|
||||
|
||||
lantiq,rx-burst-length:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
RX programmable burst length.
|
||||
enum: [2, 4, 8]
|
||||
|
||||
phy-mode: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupt-parent
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- lantiq,tx-burst-length
|
||||
- lantiq,rx-burst-length
|
||||
- phy-mode
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
ethernet@e180000 {
|
||||
compatible = "lantiq,etop-xway";
|
||||
reg = <0xe180000 0x40000>;
|
||||
interrupt-parent = <&icu0>;
|
||||
interrupts = <73>, <78>;
|
||||
interrupt-names = "tx", "rx";
|
||||
lantiq,tx-burst-length = <8>;
|
||||
lantiq,rx-burst-length = <8>;
|
||||
phy-mode = "rmii";
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
Lantiq xRX200 GSWIP PMAC Ethernet driver
|
||||
==================================
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "lantiq,xrx200-net" for the PMAC of the embedded
|
||||
: GSWIP in the xXR200
|
||||
- reg : memory range of the PMAC core inside of the GSWIP core
|
||||
- interrupts : TX and RX DMA interrupts. Use interrupt-names "tx" for
|
||||
: the TX interrupt and "rx" for the RX interrupt.
|
||||
|
||||
Example:
|
||||
|
||||
ethernet@e10b308 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "lantiq,xrx200-net";
|
||||
reg = <0xe10b308 0xcf8>;
|
||||
interrupts = <73>, <72>;
|
||||
interrupt-names = "tx", "rx";
|
||||
};
|
||||
75
Documentation/devicetree/bindings/net/lantiq,xrx200-net.yaml
Normal file
75
Documentation/devicetree/bindings/net/lantiq,xrx200-net.yaml
Normal file
@@ -0,0 +1,75 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/lantiq,xrx200-net.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Lantiq xRX200 GSWIP PMAC Ethernet driver
|
||||
|
||||
maintainers:
|
||||
- Hauke Mehrtens <hauke@hauke-m.de>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^ethernet@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: lantiq,xrx200-net
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: TX interrupt
|
||||
- description: RX interrupt
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
lantiq,tx-burst-length:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
TX programmable burst length.
|
||||
enum: [2, 4, 8]
|
||||
|
||||
lantiq,rx-burst-length:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
RX programmable burst length.
|
||||
enum: [2, 4, 8]
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupt-parent
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- lantiq,tx-burst-length
|
||||
- lantiq,rx-burst-length
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
ethernet@e10b308 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "lantiq,xrx200-net";
|
||||
reg = <0xe10b308 0xcf8>;
|
||||
interrupt-parent = <&icu0>;
|
||||
interrupts = <73>, <72>;
|
||||
interrupt-names = "tx", "rx";
|
||||
lantiq,tx-burst-length = <8>;
|
||||
lantiq,rx-burst-length = <8>;
|
||||
};
|
||||
@@ -45,6 +45,6 @@ extern void ltq_dma_close(struct ltq_dma_channel *ch);
|
||||
extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch);
|
||||
extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch);
|
||||
extern void ltq_dma_free(struct ltq_dma_channel *ch);
|
||||
extern void ltq_dma_init_port(int p);
|
||||
extern void ltq_dma_init_port(int p, int tx_burst, int rx_burst);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
@@ -30,6 +31,7 @@
|
||||
#define LTQ_DMA_PCTRL 0x44
|
||||
#define LTQ_DMA_IRNEN 0xf4
|
||||
|
||||
#define DMA_ID_CHNR GENMASK(26, 20) /* channel number */
|
||||
#define DMA_DESCPT BIT(3) /* descriptor complete irq */
|
||||
#define DMA_TX BIT(8) /* TX channel direction */
|
||||
#define DMA_CHAN_ON BIT(0) /* channel on / off bit */
|
||||
@@ -39,8 +41,11 @@
|
||||
#define DMA_IRQ_ACK 0x7e /* IRQ status register */
|
||||
#define DMA_POLL BIT(31) /* turn on channel polling */
|
||||
#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */
|
||||
#define DMA_2W_BURST BIT(1) /* 2 word burst length */
|
||||
#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */
|
||||
#define DMA_PCTRL_2W_BURST 0x1 /* 2 word burst length */
|
||||
#define DMA_PCTRL_4W_BURST 0x2 /* 4 word burst length */
|
||||
#define DMA_PCTRL_8W_BURST 0x3 /* 8 word burst length */
|
||||
#define DMA_TX_BURST_SHIFT 4 /* tx burst shift */
|
||||
#define DMA_RX_BURST_SHIFT 2 /* rx burst shift */
|
||||
#define DMA_ETOP_ENDIANNESS (0xf << 8) /* endianness swap etop channels */
|
||||
#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */
|
||||
|
||||
@@ -177,7 +182,7 @@ ltq_dma_free(struct ltq_dma_channel *ch)
|
||||
EXPORT_SYMBOL_GPL(ltq_dma_free);
|
||||
|
||||
void
|
||||
ltq_dma_init_port(int p)
|
||||
ltq_dma_init_port(int p, int tx_burst, int rx_burst)
|
||||
{
|
||||
ltq_dma_w32(p, LTQ_DMA_PS);
|
||||
switch (p) {
|
||||
@@ -186,15 +191,44 @@ ltq_dma_init_port(int p)
|
||||
* Tell the DMA engine to swap the endianness of data frames and
|
||||
* drop packets if the channel arbitration fails.
|
||||
*/
|
||||
ltq_dma_w32_mask(0, DMA_ETOP_ENDIANNESS | DMA_PDEN,
|
||||
ltq_dma_w32_mask(0, (DMA_ETOP_ENDIANNESS | DMA_PDEN),
|
||||
LTQ_DMA_PCTRL);
|
||||
break;
|
||||
|
||||
case DMA_PORT_DEU:
|
||||
ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2),
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rx_burst) {
|
||||
case 8:
|
||||
ltq_dma_w32_mask(0x0c, (DMA_PCTRL_8W_BURST << DMA_RX_BURST_SHIFT),
|
||||
LTQ_DMA_PCTRL);
|
||||
break;
|
||||
case 4:
|
||||
ltq_dma_w32_mask(0x0c, (DMA_PCTRL_4W_BURST << DMA_RX_BURST_SHIFT),
|
||||
LTQ_DMA_PCTRL);
|
||||
break;
|
||||
case 2:
|
||||
ltq_dma_w32_mask(0x0c, (DMA_PCTRL_2W_BURST << DMA_RX_BURST_SHIFT),
|
||||
LTQ_DMA_PCTRL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (tx_burst) {
|
||||
case 8:
|
||||
ltq_dma_w32_mask(0x30, (DMA_PCTRL_8W_BURST << DMA_TX_BURST_SHIFT),
|
||||
LTQ_DMA_PCTRL);
|
||||
break;
|
||||
case 4:
|
||||
ltq_dma_w32_mask(0x30, (DMA_PCTRL_4W_BURST << DMA_TX_BURST_SHIFT),
|
||||
LTQ_DMA_PCTRL);
|
||||
break;
|
||||
case 2:
|
||||
ltq_dma_w32_mask(0x30, (DMA_PCTRL_2W_BURST << DMA_TX_BURST_SHIFT),
|
||||
LTQ_DMA_PCTRL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -206,7 +240,7 @@ ltq_dma_init(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct resource *res;
|
||||
unsigned id;
|
||||
unsigned int id, nchannels;
|
||||
int i;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@@ -222,21 +256,24 @@ ltq_dma_init(struct platform_device *pdev)
|
||||
clk_enable(clk);
|
||||
ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL);
|
||||
|
||||
usleep_range(1, 10);
|
||||
|
||||
/* disable all interrupts */
|
||||
ltq_dma_w32(0, LTQ_DMA_IRNEN);
|
||||
|
||||
/* reset/configure each channel */
|
||||
for (i = 0; i < DMA_MAX_CHANNEL; i++) {
|
||||
id = ltq_dma_r32(LTQ_DMA_ID);
|
||||
nchannels = ((id & DMA_ID_CHNR) >> 20);
|
||||
for (i = 0; i < nchannels; i++) {
|
||||
ltq_dma_w32(i, LTQ_DMA_CS);
|
||||
ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL);
|
||||
ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
|
||||
ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
|
||||
}
|
||||
|
||||
id = ltq_dma_r32(LTQ_DMA_ID);
|
||||
dev_info(&pdev->dev,
|
||||
"Init done - hw rev: %X, ports: %d, channels: %d\n",
|
||||
id & 0x1f, (id >> 16) & 0xf, id >> 20);
|
||||
id & 0x1f, (id >> 16) & 0xf, nchannels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ enum HNAE3_DEV_CAP_BITS {
|
||||
HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
|
||||
HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
|
||||
HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B,
|
||||
HNAE3_DEV_SUPPORT_MC_MAC_MNG_B,
|
||||
};
|
||||
|
||||
#define hnae3_dev_fd_supported(hdev) \
|
||||
@@ -151,6 +152,9 @@ enum HNAE3_DEV_CAP_BITS {
|
||||
#define hnae3_ae_dev_rxd_adv_layout_supported(ae_dev) \
|
||||
test_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, (ae_dev)->caps)
|
||||
|
||||
#define hnae3_ae_dev_mc_mac_mng_supported(ae_dev) \
|
||||
test_bit(HNAE3_DEV_SUPPORT_MC_MAC_MNG_B, (ae_dev)->caps)
|
||||
|
||||
enum HNAE3_PF_CAP_BITS {
|
||||
HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B = 0,
|
||||
};
|
||||
@@ -341,6 +345,8 @@ struct hnae3_dev_specs {
|
||||
u8 max_non_tso_bd_num; /* max BD number of one non-TSO packet */
|
||||
u16 max_frm_size;
|
||||
u16 max_qset_num;
|
||||
u16 umv_size;
|
||||
u16 mc_mac_size;
|
||||
};
|
||||
|
||||
struct hnae3_client_ops {
|
||||
|
||||
@@ -924,6 +924,10 @@ hns3_dbg_dev_specs(struct hnae3_handle *h, char *buf, int len, int *pos)
|
||||
dev_specs->max_tm_rate);
|
||||
*pos += scnprintf(buf + *pos, len - *pos, "MAX QSET number: %u\n",
|
||||
dev_specs->max_qset_num);
|
||||
*pos += scnprintf(buf + *pos, len - *pos, "umv size: %u\n",
|
||||
dev_specs->umv_size);
|
||||
*pos += scnprintf(buf + *pos, len - *pos, "mc mac size: %u\n",
|
||||
dev_specs->mc_mac_size);
|
||||
}
|
||||
|
||||
static int hns3_dbg_dev_info(struct hnae3_handle *h, char *buf, int len)
|
||||
|
||||
@@ -1188,7 +1188,10 @@ struct hclge_dev_specs_1_cmd {
|
||||
__le16 max_frm_size;
|
||||
__le16 max_qset_num;
|
||||
__le16 max_int_gl;
|
||||
u8 rsv1[18];
|
||||
u8 rsv0[2];
|
||||
__le16 umv_size;
|
||||
__le16 mc_mac_size;
|
||||
u8 rsv1[12];
|
||||
};
|
||||
|
||||
/* mac speed type defined in firmware command */
|
||||
|
||||
@@ -1990,6 +1990,9 @@ static int hclge_dbg_dump_umv_info(struct hclge_dev *hdev, char *buf, int len)
|
||||
}
|
||||
mutex_unlock(&hdev->vport_lock);
|
||||
|
||||
pos += scnprintf(buf + pos, len - pos, "used_mc_mac_num : %u\n",
|
||||
hdev->used_mc_mac_num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1342,8 +1342,6 @@ static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
|
||||
cfg->umv_space = hnae3_get_field(__le32_to_cpu(req->param[1]),
|
||||
HCLGE_CFG_UMV_TBL_SPACE_M,
|
||||
HCLGE_CFG_UMV_TBL_SPACE_S);
|
||||
if (!cfg->umv_space)
|
||||
cfg->umv_space = HCLGE_DEFAULT_UMV_SPACE_PER_PF;
|
||||
|
||||
cfg->pf_rss_size_max = hnae3_get_field(__le32_to_cpu(req->param[2]),
|
||||
HCLGE_CFG_PF_RSS_SIZE_M,
|
||||
@@ -1419,6 +1417,7 @@ static void hclge_set_default_dev_specs(struct hclge_dev *hdev)
|
||||
ae_dev->dev_specs.max_int_gl = HCLGE_DEF_MAX_INT_GL;
|
||||
ae_dev->dev_specs.max_frm_size = HCLGE_MAC_MAX_FRAME;
|
||||
ae_dev->dev_specs.max_qset_num = HCLGE_MAX_QSET_NUM;
|
||||
ae_dev->dev_specs.umv_size = HCLGE_DEFAULT_UMV_SPACE_PER_PF;
|
||||
}
|
||||
|
||||
static void hclge_parse_dev_specs(struct hclge_dev *hdev,
|
||||
@@ -1440,6 +1439,8 @@ static void hclge_parse_dev_specs(struct hclge_dev *hdev,
|
||||
ae_dev->dev_specs.max_qset_num = le16_to_cpu(req1->max_qset_num);
|
||||
ae_dev->dev_specs.max_int_gl = le16_to_cpu(req1->max_int_gl);
|
||||
ae_dev->dev_specs.max_frm_size = le16_to_cpu(req1->max_frm_size);
|
||||
ae_dev->dev_specs.umv_size = le16_to_cpu(req1->umv_size);
|
||||
ae_dev->dev_specs.mc_mac_size = le16_to_cpu(req1->mc_mac_size);
|
||||
}
|
||||
|
||||
static void hclge_check_dev_specs(struct hclge_dev *hdev)
|
||||
@@ -1460,6 +1461,8 @@ static void hclge_check_dev_specs(struct hclge_dev *hdev)
|
||||
dev_specs->max_int_gl = HCLGE_DEF_MAX_INT_GL;
|
||||
if (!dev_specs->max_frm_size)
|
||||
dev_specs->max_frm_size = HCLGE_MAC_MAX_FRAME;
|
||||
if (!dev_specs->umv_size)
|
||||
dev_specs->umv_size = HCLGE_DEFAULT_UMV_SPACE_PER_PF;
|
||||
}
|
||||
|
||||
static int hclge_query_dev_specs(struct hclge_dev *hdev)
|
||||
@@ -1549,7 +1552,10 @@ static int hclge_configure(struct hclge_dev *hdev)
|
||||
hdev->tm_info.num_pg = 1;
|
||||
hdev->tc_max = cfg.tc_num;
|
||||
hdev->tm_info.hw_pfc_map = 0;
|
||||
hdev->wanted_umv_size = cfg.umv_space;
|
||||
if (cfg.umv_space)
|
||||
hdev->wanted_umv_size = cfg.umv_space;
|
||||
else
|
||||
hdev->wanted_umv_size = hdev->ae_dev->dev_specs.umv_size;
|
||||
hdev->tx_spare_buf_size = cfg.tx_spare_buf_size;
|
||||
hdev->gro_en = true;
|
||||
if (cfg.vlan_fliter_cap == HCLGE_VLAN_FLTR_CAN_MDF)
|
||||
@@ -8475,6 +8481,9 @@ static int hclge_init_umv_space(struct hclge_dev *hdev)
|
||||
hdev->share_umv_size = hdev->priv_umv_size +
|
||||
hdev->max_umv_size % (hdev->num_alloc_vport + 1);
|
||||
|
||||
if (hdev->ae_dev->dev_specs.mc_mac_size)
|
||||
set_bit(HNAE3_DEV_SUPPORT_MC_MAC_MNG_B, hdev->ae_dev->caps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8492,6 +8501,8 @@ static void hclge_reset_umv_space(struct hclge_dev *hdev)
|
||||
hdev->share_umv_size = hdev->priv_umv_size +
|
||||
hdev->max_umv_size % (hdev->num_alloc_vport + 1);
|
||||
mutex_unlock(&hdev->vport_lock);
|
||||
|
||||
hdev->used_mc_mac_num = 0;
|
||||
}
|
||||
|
||||
static bool hclge_is_umv_space_full(struct hclge_vport *vport, bool need_lock)
|
||||
@@ -8746,6 +8757,7 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
struct hclge_mac_vlan_tbl_entry_cmd req;
|
||||
struct hclge_desc desc[3];
|
||||
bool is_new_addr = false;
|
||||
int status;
|
||||
|
||||
/* mac addr check */
|
||||
@@ -8759,6 +8771,13 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
|
||||
hclge_prepare_mac_addr(&req, addr, true);
|
||||
status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true);
|
||||
if (status) {
|
||||
if (hnae3_ae_dev_mc_mac_mng_supported(hdev->ae_dev) &&
|
||||
hdev->used_mc_mac_num >=
|
||||
hdev->ae_dev->dev_specs.mc_mac_size)
|
||||
goto err_no_space;
|
||||
|
||||
is_new_addr = true;
|
||||
|
||||
/* This mac addr do not exist, add new entry for it */
|
||||
memset(desc[0].data, 0, sizeof(desc[0].data));
|
||||
memset(desc[1].data, 0, sizeof(desc[0].data));
|
||||
@@ -8768,12 +8787,18 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
|
||||
if (status)
|
||||
return status;
|
||||
status = hclge_add_mac_vlan_tbl(vport, &req, desc);
|
||||
/* if already overflow, not to print each time */
|
||||
if (status == -ENOSPC &&
|
||||
!(vport->overflow_promisc_flags & HNAE3_OVERFLOW_MPE))
|
||||
dev_err(&hdev->pdev->dev, "mc mac vlan table is full\n");
|
||||
if (status == -ENOSPC)
|
||||
goto err_no_space;
|
||||
else if (!status && is_new_addr)
|
||||
hdev->used_mc_mac_num++;
|
||||
|
||||
return status;
|
||||
|
||||
err_no_space:
|
||||
/* if already overflow, not to print each time */
|
||||
if (!(vport->overflow_promisc_flags & HNAE3_OVERFLOW_MPE))
|
||||
dev_err(&hdev->pdev->dev, "mc mac vlan table is full\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static int hclge_rm_mc_addr(struct hnae3_handle *handle,
|
||||
@@ -8810,12 +8835,15 @@ int hclge_rm_mc_addr_common(struct hclge_vport *vport,
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (hclge_is_all_function_id_zero(desc))
|
||||
if (hclge_is_all_function_id_zero(desc)) {
|
||||
/* All the vfid is zero, so need to delete this entry */
|
||||
status = hclge_remove_mac_vlan_tbl(vport, &req);
|
||||
else
|
||||
if (!status)
|
||||
hdev->used_mc_mac_num--;
|
||||
} else {
|
||||
/* Not all the vfid is zero, update the vfid */
|
||||
status = hclge_add_mac_vlan_tbl(vport, &req, desc);
|
||||
}
|
||||
} else if (status == -ENOENT) {
|
||||
status = 0;
|
||||
}
|
||||
|
||||
@@ -938,6 +938,8 @@ struct hclge_dev {
|
||||
u16 priv_umv_size;
|
||||
/* unicast mac vlan space shared by PF and its VFs */
|
||||
u16 share_umv_size;
|
||||
/* multicast mac address number used by PF and its VFs */
|
||||
u16 used_mc_mac_num;
|
||||
|
||||
DECLARE_KFIFO(mac_tnl_log, struct hclge_mac_tnl_stats,
|
||||
HCLGE_MAC_TNL_LOG_SIZE);
|
||||
|
||||
@@ -108,6 +108,8 @@ static int init_crq_queue(struct ibmvnic_adapter *adapter);
|
||||
static int send_query_phys_parms(struct ibmvnic_adapter *adapter);
|
||||
static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
|
||||
struct ibmvnic_sub_crq_queue *tx_scrq);
|
||||
static void free_long_term_buff(struct ibmvnic_adapter *adapter,
|
||||
struct ibmvnic_long_term_buff *ltb);
|
||||
|
||||
struct ibmvnic_stat {
|
||||
char name[ETH_GSTRING_LEN];
|
||||
@@ -214,22 +216,77 @@ static int ibmvnic_wait_for_completion(struct ibmvnic_adapter *adapter,
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* reuse_ltb() - Check if a long term buffer can be reused
|
||||
* @ltb: The long term buffer to be checked
|
||||
* @size: The size of the long term buffer.
|
||||
*
|
||||
* An LTB can be reused unless its size has changed.
|
||||
*
|
||||
* Return: Return true if the LTB can be reused, false otherwise.
|
||||
*/
|
||||
static bool reuse_ltb(struct ibmvnic_long_term_buff *ltb, int size)
|
||||
{
|
||||
return (ltb->buff && ltb->size == size);
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_long_term_buff() - Allocate a long term buffer (LTB)
|
||||
*
|
||||
* @adapter: ibmvnic adapter associated to the LTB
|
||||
* @ltb: container object for the LTB
|
||||
* @size: size of the LTB
|
||||
*
|
||||
* Allocate an LTB of the specified size and notify VIOS.
|
||||
*
|
||||
* If the given @ltb already has the correct size, reuse it. Otherwise if
|
||||
* its non-NULL, free it. Then allocate a new one of the correct size.
|
||||
* Notify the VIOS either way since we may now be working with a new VIOS.
|
||||
*
|
||||
* Allocating larger chunks of memory during resets, specially LPM or under
|
||||
* low memory situations can cause resets to fail/timeout and for LPAR to
|
||||
* lose connectivity. So hold onto the LTB even if we fail to communicate
|
||||
* with the VIOS and reuse it on next open. Free LTB when adapter is closed.
|
||||
*
|
||||
* Return: 0 if we were able to allocate the LTB and notify the VIOS and
|
||||
* a negative value otherwise.
|
||||
*/
|
||||
static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
|
||||
struct ibmvnic_long_term_buff *ltb, int size)
|
||||
{
|
||||
struct device *dev = &adapter->vdev->dev;
|
||||
int rc;
|
||||
|
||||
ltb->size = size;
|
||||
ltb->buff = dma_alloc_coherent(dev, ltb->size, <b->addr,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!ltb->buff) {
|
||||
dev_err(dev, "Couldn't alloc long term buffer\n");
|
||||
return -ENOMEM;
|
||||
if (!reuse_ltb(ltb, size)) {
|
||||
dev_dbg(dev,
|
||||
"LTB size changed from 0x%llx to 0x%x, reallocating\n",
|
||||
ltb->size, size);
|
||||
free_long_term_buff(adapter, ltb);
|
||||
}
|
||||
ltb->map_id = adapter->map_id;
|
||||
adapter->map_id++;
|
||||
|
||||
if (ltb->buff) {
|
||||
dev_dbg(dev, "Reusing LTB [map %d, size 0x%llx]\n",
|
||||
ltb->map_id, ltb->size);
|
||||
} else {
|
||||
ltb->buff = dma_alloc_coherent(dev, size, <b->addr,
|
||||
GFP_KERNEL);
|
||||
if (!ltb->buff) {
|
||||
dev_err(dev, "Couldn't alloc long term buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ltb->size = size;
|
||||
|
||||
ltb->map_id = find_first_zero_bit(adapter->map_ids,
|
||||
MAX_MAP_ID);
|
||||
bitmap_set(adapter->map_ids, ltb->map_id, 1);
|
||||
|
||||
dev_dbg(dev,
|
||||
"Allocated new LTB [map %d, size 0x%llx]\n",
|
||||
ltb->map_id, ltb->size);
|
||||
}
|
||||
|
||||
/* Ensure ltb is zeroed - specially when reusing it. */
|
||||
memset(ltb->buff, 0, ltb->size);
|
||||
|
||||
mutex_lock(&adapter->fw_lock);
|
||||
adapter->fw_done_rc = 0;
|
||||
@@ -243,24 +300,20 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
|
||||
|
||||
rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
|
||||
if (rc) {
|
||||
dev_err(dev,
|
||||
"Long term map request aborted or timed out,rc = %d\n",
|
||||
dev_err(dev, "LTB map request aborted or timed out, rc = %d\n",
|
||||
rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (adapter->fw_done_rc) {
|
||||
dev_err(dev, "Couldn't map long term buffer,rc = %d\n",
|
||||
dev_err(dev, "Couldn't map LTB, rc = %d\n",
|
||||
adapter->fw_done_rc);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
out:
|
||||
if (rc) {
|
||||
dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
|
||||
ltb->buff = NULL;
|
||||
}
|
||||
/* don't free LTB on communication error - see function header */
|
||||
mutex_unlock(&adapter->fw_lock);
|
||||
return rc;
|
||||
}
|
||||
@@ -281,48 +334,15 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter,
|
||||
adapter->reset_reason != VNIC_RESET_MOBILITY &&
|
||||
adapter->reset_reason != VNIC_RESET_TIMEOUT)
|
||||
send_request_unmap(adapter, ltb->map_id);
|
||||
|
||||
dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
|
||||
|
||||
ltb->buff = NULL;
|
||||
/* mark this map_id free */
|
||||
bitmap_clear(adapter->map_ids, ltb->map_id, 1);
|
||||
ltb->map_id = 0;
|
||||
}
|
||||
|
||||
static int reset_long_term_buff(struct ibmvnic_adapter *adapter,
|
||||
struct ibmvnic_long_term_buff *ltb)
|
||||
{
|
||||
struct device *dev = &adapter->vdev->dev;
|
||||
int rc;
|
||||
|
||||
memset(ltb->buff, 0, ltb->size);
|
||||
|
||||
mutex_lock(&adapter->fw_lock);
|
||||
adapter->fw_done_rc = 0;
|
||||
|
||||
reinit_completion(&adapter->fw_done);
|
||||
rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
|
||||
if (rc) {
|
||||
mutex_unlock(&adapter->fw_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
|
||||
if (rc) {
|
||||
dev_info(dev,
|
||||
"Reset failed, long term map request timed out or aborted\n");
|
||||
mutex_unlock(&adapter->fw_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (adapter->fw_done_rc) {
|
||||
dev_info(dev,
|
||||
"Reset failed, attempting to free and reallocate buffer\n");
|
||||
free_long_term_buff(adapter, ltb);
|
||||
mutex_unlock(&adapter->fw_lock);
|
||||
return alloc_long_term_buff(adapter, ltb, ltb->size);
|
||||
}
|
||||
mutex_unlock(&adapter->fw_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void deactivate_rx_pools(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
@@ -363,31 +383,41 @@ static void replenish_rx_pool(struct ibmvnic_adapter *adapter,
|
||||
* be 0.
|
||||
*/
|
||||
for (i = ind_bufp->index; i < count; ++i) {
|
||||
skb = netdev_alloc_skb(adapter->netdev, pool->buff_size);
|
||||
if (!skb) {
|
||||
dev_err(dev, "Couldn't replenish rx buff\n");
|
||||
adapter->replenish_no_mem++;
|
||||
break;
|
||||
}
|
||||
|
||||
index = pool->free_map[pool->next_free];
|
||||
|
||||
if (pool->rx_buff[index].skb)
|
||||
dev_err(dev, "Inconsistent free_map!\n");
|
||||
/* We maybe reusing the skb from earlier resets. Allocate
|
||||
* only if necessary. But since the LTB may have changed
|
||||
* during reset (see init_rx_pools()), update LTB below
|
||||
* even if reusing skb.
|
||||
*/
|
||||
skb = pool->rx_buff[index].skb;
|
||||
if (!skb) {
|
||||
skb = netdev_alloc_skb(adapter->netdev,
|
||||
pool->buff_size);
|
||||
if (!skb) {
|
||||
dev_err(dev, "Couldn't replenish rx buff\n");
|
||||
adapter->replenish_no_mem++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pool->free_map[pool->next_free] = IBMVNIC_INVALID_MAP;
|
||||
pool->next_free = (pool->next_free + 1) % pool->size;
|
||||
|
||||
/* Copy the skb to the long term mapped DMA buffer */
|
||||
offset = index * pool->buff_size;
|
||||
dst = pool->long_term_buff.buff + offset;
|
||||
memset(dst, 0, pool->buff_size);
|
||||
dma_addr = pool->long_term_buff.addr + offset;
|
||||
pool->rx_buff[index].data = dst;
|
||||
|
||||
pool->free_map[pool->next_free] = IBMVNIC_INVALID_MAP;
|
||||
/* add the skb to an rx_buff in the pool */
|
||||
pool->rx_buff[index].data = dst;
|
||||
pool->rx_buff[index].dma = dma_addr;
|
||||
pool->rx_buff[index].skb = skb;
|
||||
pool->rx_buff[index].pool_index = pool->index;
|
||||
pool->rx_buff[index].size = pool->buff_size;
|
||||
|
||||
/* queue the rx_buff for the next send_subcrq_indirect */
|
||||
sub_crq = &ind_bufp->indir_arr[ind_bufp->index++];
|
||||
memset(sub_crq, 0, sizeof(*sub_crq));
|
||||
sub_crq->rx_add.first = IBMVNIC_CRQ_CMD;
|
||||
@@ -405,7 +435,8 @@ static void replenish_rx_pool(struct ibmvnic_adapter *adapter,
|
||||
shift = 8;
|
||||
#endif
|
||||
sub_crq->rx_add.len = cpu_to_be32(pool->buff_size << shift);
|
||||
pool->next_free = (pool->next_free + 1) % pool->size;
|
||||
|
||||
/* if send_subcrq_indirect queue is full, flush to VIOS */
|
||||
if (ind_bufp->index == IBMVNIC_MAX_IND_DESCS ||
|
||||
i == count - 1) {
|
||||
lpar_rc =
|
||||
@@ -523,53 +554,12 @@ static int init_stats_token(struct ibmvnic_adapter *adapter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_rx_pools(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
struct ibmvnic_rx_pool *rx_pool;
|
||||
u64 buff_size;
|
||||
int rx_scrqs;
|
||||
int i, j, rc;
|
||||
|
||||
if (!adapter->rx_pool)
|
||||
return -1;
|
||||
|
||||
buff_size = adapter->cur_rx_buf_sz;
|
||||
rx_scrqs = adapter->num_active_rx_pools;
|
||||
for (i = 0; i < rx_scrqs; i++) {
|
||||
rx_pool = &adapter->rx_pool[i];
|
||||
|
||||
netdev_dbg(adapter->netdev, "Re-setting rx_pool[%d]\n", i);
|
||||
|
||||
if (rx_pool->buff_size != buff_size) {
|
||||
free_long_term_buff(adapter, &rx_pool->long_term_buff);
|
||||
rx_pool->buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
|
||||
rc = alloc_long_term_buff(adapter,
|
||||
&rx_pool->long_term_buff,
|
||||
rx_pool->size *
|
||||
rx_pool->buff_size);
|
||||
} else {
|
||||
rc = reset_long_term_buff(adapter,
|
||||
&rx_pool->long_term_buff);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (j = 0; j < rx_pool->size; j++)
|
||||
rx_pool->free_map[j] = j;
|
||||
|
||||
memset(rx_pool->rx_buff, 0,
|
||||
rx_pool->size * sizeof(struct ibmvnic_rx_buff));
|
||||
|
||||
atomic_set(&rx_pool->available, 0);
|
||||
rx_pool->next_alloc = 0;
|
||||
rx_pool->next_free = 0;
|
||||
rx_pool->active = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* release_rx_pools() - Release any rx pools attached to @adapter.
|
||||
* @adapter: ibmvnic adapter
|
||||
*
|
||||
* Safe to call this multiple times - even if no pools are attached.
|
||||
*/
|
||||
static void release_rx_pools(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
struct ibmvnic_rx_pool *rx_pool;
|
||||
@@ -584,6 +574,7 @@ static void release_rx_pools(struct ibmvnic_adapter *adapter)
|
||||
netdev_dbg(adapter->netdev, "Releasing rx_pool[%d]\n", i);
|
||||
|
||||
kfree(rx_pool->free_map);
|
||||
|
||||
free_long_term_buff(adapter, &rx_pool->long_term_buff);
|
||||
|
||||
if (!rx_pool->rx_buff)
|
||||
@@ -602,21 +593,91 @@ static void release_rx_pools(struct ibmvnic_adapter *adapter)
|
||||
kfree(adapter->rx_pool);
|
||||
adapter->rx_pool = NULL;
|
||||
adapter->num_active_rx_pools = 0;
|
||||
adapter->prev_rx_pool_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* reuse_rx_pools() - Check if the existing rx pools can be reused.
|
||||
* @adapter: ibmvnic adapter
|
||||
*
|
||||
* Check if the existing rx pools in the adapter can be reused. The
|
||||
* pools can be reused if the pool parameters (number of pools,
|
||||
* number of buffers in the pool and size of each buffer) have not
|
||||
* changed.
|
||||
*
|
||||
* NOTE: This assumes that all pools have the same number of buffers
|
||||
* which is the case currently. If that changes, we must fix this.
|
||||
*
|
||||
* Return: true if the rx pools can be reused, false otherwise.
|
||||
*/
|
||||
static bool reuse_rx_pools(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
u64 old_num_pools, new_num_pools;
|
||||
u64 old_pool_size, new_pool_size;
|
||||
u64 old_buff_size, new_buff_size;
|
||||
|
||||
if (!adapter->rx_pool)
|
||||
return false;
|
||||
|
||||
old_num_pools = adapter->num_active_rx_pools;
|
||||
new_num_pools = adapter->req_rx_queues;
|
||||
|
||||
old_pool_size = adapter->prev_rx_pool_size;
|
||||
new_pool_size = adapter->req_rx_add_entries_per_subcrq;
|
||||
|
||||
old_buff_size = adapter->prev_rx_buf_sz;
|
||||
new_buff_size = adapter->cur_rx_buf_sz;
|
||||
|
||||
/* Require buff size to be exactly same for now */
|
||||
if (old_buff_size != new_buff_size)
|
||||
return false;
|
||||
|
||||
if (old_num_pools == new_num_pools && old_pool_size == new_pool_size)
|
||||
return true;
|
||||
|
||||
if (old_num_pools < adapter->min_rx_queues ||
|
||||
old_num_pools > adapter->max_rx_queues ||
|
||||
old_pool_size < adapter->min_rx_add_entries_per_subcrq ||
|
||||
old_pool_size > adapter->max_rx_add_entries_per_subcrq)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* init_rx_pools(): Initialize the set of receiver pools in the adapter.
|
||||
* @netdev: net device associated with the vnic interface
|
||||
*
|
||||
* Initialize the set of receiver pools in the ibmvnic adapter associated
|
||||
* with the net_device @netdev. If possible, reuse the existing rx pools.
|
||||
* Otherwise free any existing pools and allocate a new set of pools
|
||||
* before initializing them.
|
||||
*
|
||||
* Return: 0 on success and negative value on error.
|
||||
*/
|
||||
static int init_rx_pools(struct net_device *netdev)
|
||||
{
|
||||
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
||||
struct device *dev = &adapter->vdev->dev;
|
||||
struct ibmvnic_rx_pool *rx_pool;
|
||||
int rxadd_subcrqs;
|
||||
u64 num_pools;
|
||||
u64 pool_size; /* # of buffers in one pool */
|
||||
u64 buff_size;
|
||||
int i, j;
|
||||
|
||||
rxadd_subcrqs = adapter->num_active_rx_scrqs;
|
||||
pool_size = adapter->req_rx_add_entries_per_subcrq;
|
||||
num_pools = adapter->req_rx_queues;
|
||||
buff_size = adapter->cur_rx_buf_sz;
|
||||
|
||||
adapter->rx_pool = kcalloc(rxadd_subcrqs,
|
||||
if (reuse_rx_pools(adapter)) {
|
||||
dev_dbg(dev, "Reusing rx pools\n");
|
||||
goto update_ltb;
|
||||
}
|
||||
|
||||
/* Allocate/populate the pools. */
|
||||
release_rx_pools(adapter);
|
||||
|
||||
adapter->rx_pool = kcalloc(num_pools,
|
||||
sizeof(struct ibmvnic_rx_pool),
|
||||
GFP_KERNEL);
|
||||
if (!adapter->rx_pool) {
|
||||
@@ -624,26 +685,27 @@ static int init_rx_pools(struct net_device *netdev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
adapter->num_active_rx_pools = rxadd_subcrqs;
|
||||
/* Set num_active_rx_pools early. If we fail below after partial
|
||||
* allocation, release_rx_pools() will know how many to look for.
|
||||
*/
|
||||
adapter->num_active_rx_pools = num_pools;
|
||||
|
||||
for (i = 0; i < rxadd_subcrqs; i++) {
|
||||
for (i = 0; i < num_pools; i++) {
|
||||
rx_pool = &adapter->rx_pool[i];
|
||||
|
||||
netdev_dbg(adapter->netdev,
|
||||
"Initializing rx_pool[%d], %lld buffs, %lld bytes each\n",
|
||||
i, adapter->req_rx_add_entries_per_subcrq,
|
||||
buff_size);
|
||||
i, pool_size, buff_size);
|
||||
|
||||
rx_pool->size = adapter->req_rx_add_entries_per_subcrq;
|
||||
rx_pool->size = pool_size;
|
||||
rx_pool->index = i;
|
||||
rx_pool->buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
|
||||
rx_pool->active = 1;
|
||||
|
||||
rx_pool->free_map = kcalloc(rx_pool->size, sizeof(int),
|
||||
GFP_KERNEL);
|
||||
if (!rx_pool->free_map) {
|
||||
release_rx_pools(adapter);
|
||||
return -1;
|
||||
dev_err(dev, "Couldn't alloc free_map %d\n", i);
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
rx_pool->rx_buff = kcalloc(rx_pool->size,
|
||||
@@ -651,69 +713,58 @@ static int init_rx_pools(struct net_device *netdev)
|
||||
GFP_KERNEL);
|
||||
if (!rx_pool->rx_buff) {
|
||||
dev_err(dev, "Couldn't alloc rx buffers\n");
|
||||
release_rx_pools(adapter);
|
||||
return -1;
|
||||
goto out_release;
|
||||
}
|
||||
}
|
||||
|
||||
adapter->prev_rx_pool_size = pool_size;
|
||||
adapter->prev_rx_buf_sz = adapter->cur_rx_buf_sz;
|
||||
|
||||
update_ltb:
|
||||
for (i = 0; i < num_pools; i++) {
|
||||
rx_pool = &adapter->rx_pool[i];
|
||||
dev_dbg(dev, "Updating LTB for rx pool %d [%d, %d]\n",
|
||||
i, rx_pool->size, rx_pool->buff_size);
|
||||
|
||||
if (alloc_long_term_buff(adapter, &rx_pool->long_term_buff,
|
||||
rx_pool->size * rx_pool->buff_size)) {
|
||||
release_rx_pools(adapter);
|
||||
return -1;
|
||||
}
|
||||
rx_pool->size * rx_pool->buff_size))
|
||||
goto out;
|
||||
|
||||
for (j = 0; j < rx_pool->size; ++j) {
|
||||
struct ibmvnic_rx_buff *rx_buff;
|
||||
|
||||
for (j = 0; j < rx_pool->size; ++j)
|
||||
rx_pool->free_map[j] = j;
|
||||
|
||||
/* NOTE: Don't clear rx_buff->skb here - will leak
|
||||
* memory! replenish_rx_pool() will reuse skbs or
|
||||
* allocate as necessary.
|
||||
*/
|
||||
rx_buff = &rx_pool->rx_buff[j];
|
||||
rx_buff->dma = 0;
|
||||
rx_buff->data = 0;
|
||||
rx_buff->size = 0;
|
||||
rx_buff->pool_index = 0;
|
||||
}
|
||||
|
||||
/* Mark pool "empty" so replenish_rx_pools() will
|
||||
* update the LTB info for each buffer
|
||||
*/
|
||||
atomic_set(&rx_pool->available, 0);
|
||||
rx_pool->next_alloc = 0;
|
||||
rx_pool->next_free = 0;
|
||||
/* replenish_rx_pool() may have called deactivate_rx_pools()
|
||||
* on failover. Ensure pool is active now.
|
||||
*/
|
||||
rx_pool->active = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_one_tx_pool(struct ibmvnic_adapter *adapter,
|
||||
struct ibmvnic_tx_pool *tx_pool)
|
||||
{
|
||||
int rc, i;
|
||||
|
||||
rc = reset_long_term_buff(adapter, &tx_pool->long_term_buff);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
memset(tx_pool->tx_buff, 0,
|
||||
tx_pool->num_buffers *
|
||||
sizeof(struct ibmvnic_tx_buff));
|
||||
|
||||
for (i = 0; i < tx_pool->num_buffers; i++)
|
||||
tx_pool->free_map[i] = i;
|
||||
|
||||
tx_pool->consumer_index = 0;
|
||||
tx_pool->producer_index = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_tx_pools(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
int tx_scrqs;
|
||||
int i, rc;
|
||||
|
||||
if (!adapter->tx_pool)
|
||||
return -1;
|
||||
|
||||
tx_scrqs = adapter->num_active_tx_pools;
|
||||
for (i = 0; i < tx_scrqs; i++) {
|
||||
ibmvnic_tx_scrq_clean_buffer(adapter, adapter->tx_scrq[i]);
|
||||
rc = reset_one_tx_pool(adapter, &adapter->tso_pool[i]);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = reset_one_tx_pool(adapter, &adapter->tx_pool[i]);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_release:
|
||||
release_rx_pools(adapter);
|
||||
out:
|
||||
/* We failed to allocate one or more LTBs or map them on the VIOS.
|
||||
* Hold onto the pools and any LTBs that we did allocate/map.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void release_vpd_data(struct ibmvnic_adapter *adapter)
|
||||
@@ -735,10 +786,19 @@ static void release_one_tx_pool(struct ibmvnic_adapter *adapter,
|
||||
free_long_term_buff(adapter, &tx_pool->long_term_buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* release_tx_pools() - Release any tx pools attached to @adapter.
|
||||
* @adapter: ibmvnic adapter
|
||||
*
|
||||
* Safe to call this multiple times - even if no pools are attached.
|
||||
*/
|
||||
static void release_tx_pools(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* init_tx_pools() ensures that ->tx_pool and ->tso_pool are
|
||||
* both NULL or both non-NULL. So we only need to check one.
|
||||
*/
|
||||
if (!adapter->tx_pool)
|
||||
return;
|
||||
|
||||
@@ -752,84 +812,218 @@ static void release_tx_pools(struct ibmvnic_adapter *adapter)
|
||||
kfree(adapter->tso_pool);
|
||||
adapter->tso_pool = NULL;
|
||||
adapter->num_active_tx_pools = 0;
|
||||
adapter->prev_tx_pool_size = 0;
|
||||
}
|
||||
|
||||
static int init_one_tx_pool(struct net_device *netdev,
|
||||
struct ibmvnic_tx_pool *tx_pool,
|
||||
int num_entries, int buf_size)
|
||||
int pool_size, int buf_size)
|
||||
{
|
||||
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
||||
int i;
|
||||
|
||||
tx_pool->tx_buff = kcalloc(num_entries,
|
||||
tx_pool->tx_buff = kcalloc(pool_size,
|
||||
sizeof(struct ibmvnic_tx_buff),
|
||||
GFP_KERNEL);
|
||||
if (!tx_pool->tx_buff)
|
||||
return -1;
|
||||
|
||||
if (alloc_long_term_buff(adapter, &tx_pool->long_term_buff,
|
||||
num_entries * buf_size))
|
||||
tx_pool->free_map = kcalloc(pool_size, sizeof(int), GFP_KERNEL);
|
||||
if (!tx_pool->free_map) {
|
||||
kfree(tx_pool->tx_buff);
|
||||
tx_pool->tx_buff = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tx_pool->free_map = kcalloc(num_entries, sizeof(int), GFP_KERNEL);
|
||||
if (!tx_pool->free_map)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < num_entries; i++)
|
||||
for (i = 0; i < pool_size; i++)
|
||||
tx_pool->free_map[i] = i;
|
||||
|
||||
tx_pool->consumer_index = 0;
|
||||
tx_pool->producer_index = 0;
|
||||
tx_pool->num_buffers = num_entries;
|
||||
tx_pool->num_buffers = pool_size;
|
||||
tx_pool->buf_size = buf_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* reuse_tx_pools() - Check if the existing tx pools can be reused.
|
||||
* @adapter: ibmvnic adapter
|
||||
*
|
||||
* Check if the existing tx pools in the adapter can be reused. The
|
||||
* pools can be reused if the pool parameters (number of pools,
|
||||
* number of buffers in the pool and mtu) have not changed.
|
||||
*
|
||||
* NOTE: This assumes that all pools have the same number of buffers
|
||||
* which is the case currently. If that changes, we must fix this.
|
||||
*
|
||||
* Return: true if the tx pools can be reused, false otherwise.
|
||||
*/
|
||||
static bool reuse_tx_pools(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
u64 old_num_pools, new_num_pools;
|
||||
u64 old_pool_size, new_pool_size;
|
||||
u64 old_mtu, new_mtu;
|
||||
|
||||
if (!adapter->tx_pool)
|
||||
return false;
|
||||
|
||||
old_num_pools = adapter->num_active_tx_pools;
|
||||
new_num_pools = adapter->num_active_tx_scrqs;
|
||||
old_pool_size = adapter->prev_tx_pool_size;
|
||||
new_pool_size = adapter->req_tx_entries_per_subcrq;
|
||||
old_mtu = adapter->prev_mtu;
|
||||
new_mtu = adapter->req_mtu;
|
||||
|
||||
/* Require MTU to be exactly same to reuse pools for now */
|
||||
if (old_mtu != new_mtu)
|
||||
return false;
|
||||
|
||||
if (old_num_pools == new_num_pools && old_pool_size == new_pool_size)
|
||||
return true;
|
||||
|
||||
if (old_num_pools < adapter->min_tx_queues ||
|
||||
old_num_pools > adapter->max_tx_queues ||
|
||||
old_pool_size < adapter->min_tx_entries_per_subcrq ||
|
||||
old_pool_size > adapter->max_tx_entries_per_subcrq)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* init_tx_pools(): Initialize the set of transmit pools in the adapter.
|
||||
* @netdev: net device associated with the vnic interface
|
||||
*
|
||||
* Initialize the set of transmit pools in the ibmvnic adapter associated
|
||||
* with the net_device @netdev. If possible, reuse the existing tx pools.
|
||||
* Otherwise free any existing pools and allocate a new set of pools
|
||||
* before initializing them.
|
||||
*
|
||||
* Return: 0 on success and negative value on error.
|
||||
*/
|
||||
static int init_tx_pools(struct net_device *netdev)
|
||||
{
|
||||
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
||||
int tx_subcrqs;
|
||||
struct device *dev = &adapter->vdev->dev;
|
||||
int num_pools;
|
||||
u64 pool_size; /* # of buffers in pool */
|
||||
u64 buff_size;
|
||||
int i, rc;
|
||||
int i, j, rc;
|
||||
|
||||
tx_subcrqs = adapter->num_active_tx_scrqs;
|
||||
adapter->tx_pool = kcalloc(tx_subcrqs,
|
||||
num_pools = adapter->req_tx_queues;
|
||||
|
||||
/* We must notify the VIOS about the LTB on all resets - but we only
|
||||
* need to alloc/populate pools if either the number of buffers or
|
||||
* size of each buffer in the pool has changed.
|
||||
*/
|
||||
if (reuse_tx_pools(adapter)) {
|
||||
netdev_dbg(netdev, "Reusing tx pools\n");
|
||||
goto update_ltb;
|
||||
}
|
||||
|
||||
/* Allocate/populate the pools. */
|
||||
release_tx_pools(adapter);
|
||||
|
||||
pool_size = adapter->req_tx_entries_per_subcrq;
|
||||
num_pools = adapter->num_active_tx_scrqs;
|
||||
|
||||
adapter->tx_pool = kcalloc(num_pools,
|
||||
sizeof(struct ibmvnic_tx_pool), GFP_KERNEL);
|
||||
if (!adapter->tx_pool)
|
||||
return -1;
|
||||
|
||||
adapter->tso_pool = kcalloc(tx_subcrqs,
|
||||
adapter->tso_pool = kcalloc(num_pools,
|
||||
sizeof(struct ibmvnic_tx_pool), GFP_KERNEL);
|
||||
/* To simplify release_tx_pools() ensure that ->tx_pool and
|
||||
* ->tso_pool are either both NULL or both non-NULL.
|
||||
*/
|
||||
if (!adapter->tso_pool) {
|
||||
kfree(adapter->tx_pool);
|
||||
adapter->tx_pool = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
adapter->num_active_tx_pools = tx_subcrqs;
|
||||
/* Set num_active_tx_pools early. If we fail below after partial
|
||||
* allocation, release_tx_pools() will know how many to look for.
|
||||
*/
|
||||
adapter->num_active_tx_pools = num_pools;
|
||||
|
||||
buff_size = adapter->req_mtu + VLAN_HLEN;
|
||||
buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
|
||||
|
||||
for (i = 0; i < num_pools; i++) {
|
||||
dev_dbg(dev, "Init tx pool %d [%llu, %llu]\n",
|
||||
i, adapter->req_tx_entries_per_subcrq, buff_size);
|
||||
|
||||
for (i = 0; i < tx_subcrqs; i++) {
|
||||
buff_size = adapter->req_mtu + VLAN_HLEN;
|
||||
buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
|
||||
rc = init_one_tx_pool(netdev, &adapter->tx_pool[i],
|
||||
adapter->req_tx_entries_per_subcrq,
|
||||
buff_size);
|
||||
if (rc) {
|
||||
release_tx_pools(adapter);
|
||||
return rc;
|
||||
}
|
||||
pool_size, buff_size);
|
||||
if (rc)
|
||||
goto out_release;
|
||||
|
||||
rc = init_one_tx_pool(netdev, &adapter->tso_pool[i],
|
||||
IBMVNIC_TSO_BUFS,
|
||||
IBMVNIC_TSO_BUF_SZ);
|
||||
if (rc) {
|
||||
release_tx_pools(adapter);
|
||||
return rc;
|
||||
}
|
||||
if (rc)
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
adapter->prev_tx_pool_size = pool_size;
|
||||
adapter->prev_mtu = adapter->req_mtu;
|
||||
|
||||
update_ltb:
|
||||
/* NOTE: All tx_pools have the same number of buffers (which is
|
||||
* same as pool_size). All tso_pools have IBMVNIC_TSO_BUFS
|
||||
* buffers (see calls init_one_tx_pool() for these).
|
||||
* For consistency, we use tx_pool->num_buffers and
|
||||
* tso_pool->num_buffers below.
|
||||
*/
|
||||
rc = -1;
|
||||
for (i = 0; i < num_pools; i++) {
|
||||
struct ibmvnic_tx_pool *tso_pool;
|
||||
struct ibmvnic_tx_pool *tx_pool;
|
||||
u32 ltb_size;
|
||||
|
||||
tx_pool = &adapter->tx_pool[i];
|
||||
ltb_size = tx_pool->num_buffers * tx_pool->buf_size;
|
||||
if (alloc_long_term_buff(adapter, &tx_pool->long_term_buff,
|
||||
ltb_size))
|
||||
goto out;
|
||||
|
||||
dev_dbg(dev, "Updated LTB for tx pool %d [%p, %d, %d]\n",
|
||||
i, tx_pool->long_term_buff.buff,
|
||||
tx_pool->num_buffers, tx_pool->buf_size);
|
||||
|
||||
tx_pool->consumer_index = 0;
|
||||
tx_pool->producer_index = 0;
|
||||
|
||||
for (j = 0; j < tx_pool->num_buffers; j++)
|
||||
tx_pool->free_map[j] = j;
|
||||
|
||||
tso_pool = &adapter->tso_pool[i];
|
||||
ltb_size = tso_pool->num_buffers * tso_pool->buf_size;
|
||||
if (alloc_long_term_buff(adapter, &tso_pool->long_term_buff,
|
||||
ltb_size))
|
||||
goto out;
|
||||
|
||||
dev_dbg(dev, "Updated LTB for tso pool %d [%p, %d, %d]\n",
|
||||
i, tso_pool->long_term_buff.buff,
|
||||
tso_pool->num_buffers, tso_pool->buf_size);
|
||||
|
||||
tso_pool->consumer_index = 0;
|
||||
tso_pool->producer_index = 0;
|
||||
|
||||
for (j = 0; j < tso_pool->num_buffers; j++)
|
||||
tso_pool->free_map[j] = j;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_release:
|
||||
release_tx_pools(adapter);
|
||||
out:
|
||||
/* We failed to allocate one or more LTBs or map them on the VIOS.
|
||||
* Hold onto the pools and any LTBs that we did allocate/map.
|
||||
*/
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ibmvnic_napi_enable(struct ibmvnic_adapter *adapter)
|
||||
@@ -1020,9 +1214,6 @@ static void release_resources(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
release_vpd_data(adapter);
|
||||
|
||||
release_tx_pools(adapter);
|
||||
release_rx_pools(adapter);
|
||||
|
||||
release_napi(adapter);
|
||||
release_login_buffer(adapter);
|
||||
release_login_rsp_buffer(adapter);
|
||||
@@ -1198,8 +1389,6 @@ static int init_resources(struct ibmvnic_adapter *adapter)
|
||||
return rc;
|
||||
}
|
||||
|
||||
adapter->map_id = 1;
|
||||
|
||||
rc = init_napi(adapter);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -1296,6 +1485,8 @@ static int ibmvnic_open(struct net_device *netdev)
|
||||
if (rc) {
|
||||
netdev_err(netdev, "failed to initialize resources\n");
|
||||
release_resources(adapter);
|
||||
release_rx_pools(adapter);
|
||||
release_tx_pools(adapter);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1424,9 +1615,6 @@ static void ibmvnic_cleanup(struct net_device *netdev)
|
||||
|
||||
ibmvnic_napi_disable(adapter);
|
||||
ibmvnic_disable_irqs(adapter);
|
||||
|
||||
clean_rx_pools(adapter);
|
||||
clean_tx_pools(adapter);
|
||||
}
|
||||
|
||||
static int __ibmvnic_close(struct net_device *netdev)
|
||||
@@ -1460,6 +1648,8 @@ static int ibmvnic_close(struct net_device *netdev)
|
||||
|
||||
rc = __ibmvnic_close(netdev);
|
||||
ibmvnic_cleanup(netdev);
|
||||
clean_rx_pools(adapter);
|
||||
clean_tx_pools(adapter);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -2036,9 +2226,9 @@ static const char *reset_reason_to_string(enum ibmvnic_reset_reason reason)
|
||||
static int do_reset(struct ibmvnic_adapter *adapter,
|
||||
struct ibmvnic_rwi *rwi, u32 reset_state)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
u64 old_num_rx_queues, old_num_tx_queues;
|
||||
u64 old_num_rx_slots, old_num_tx_slots;
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
int rc;
|
||||
|
||||
netdev_dbg(adapter->netdev,
|
||||
@@ -2188,8 +2378,6 @@ static int do_reset(struct ibmvnic_adapter *adapter,
|
||||
!adapter->rx_pool ||
|
||||
!adapter->tso_pool ||
|
||||
!adapter->tx_pool) {
|
||||
release_rx_pools(adapter);
|
||||
release_tx_pools(adapter);
|
||||
release_napi(adapter);
|
||||
release_vpd_data(adapter);
|
||||
|
||||
@@ -2198,16 +2386,18 @@ static int do_reset(struct ibmvnic_adapter *adapter,
|
||||
goto out;
|
||||
|
||||
} else {
|
||||
rc = reset_tx_pools(adapter);
|
||||
rc = init_tx_pools(netdev);
|
||||
if (rc) {
|
||||
netdev_dbg(adapter->netdev, "reset tx pools failed (%d)\n",
|
||||
netdev_dbg(netdev,
|
||||
"init tx pools failed (%d)\n",
|
||||
rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = reset_rx_pools(adapter);
|
||||
rc = init_rx_pools(netdev);
|
||||
if (rc) {
|
||||
netdev_dbg(adapter->netdev, "reset rx pools failed (%d)\n",
|
||||
netdev_dbg(netdev,
|
||||
"init rx pools failed (%d)\n",
|
||||
rc);
|
||||
goto out;
|
||||
}
|
||||
@@ -4778,9 +4968,10 @@ static void handle_query_map_rsp(union ibmvnic_crq *crq,
|
||||
dev_err(dev, "Error %ld in QUERY_MAP_RSP\n", rc);
|
||||
return;
|
||||
}
|
||||
netdev_dbg(netdev, "page_size = %d\ntot_pages = %d\nfree_pages = %d\n",
|
||||
crq->query_map_rsp.page_size, crq->query_map_rsp.tot_pages,
|
||||
crq->query_map_rsp.free_pages);
|
||||
netdev_dbg(netdev, "page_size = %d\ntot_pages = %u\nfree_pages = %u\n",
|
||||
crq->query_map_rsp.page_size,
|
||||
__be32_to_cpu(crq->query_map_rsp.tot_pages),
|
||||
__be32_to_cpu(crq->query_map_rsp.free_pages));
|
||||
}
|
||||
|
||||
static void handle_query_cap_rsp(union ibmvnic_crq *crq,
|
||||
@@ -5527,6 +5718,9 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
adapter->vdev = dev;
|
||||
adapter->netdev = netdev;
|
||||
adapter->login_pending = false;
|
||||
memset(&adapter->map_ids, 0, sizeof(adapter->map_ids));
|
||||
/* map_ids start at 1, so ensure map_id 0 is always "in-use" */
|
||||
bitmap_set(adapter->map_ids, 0, 1);
|
||||
|
||||
ether_addr_copy(adapter->mac_addr, mac_addr_p);
|
||||
ether_addr_copy(netdev->dev_addr, adapter->mac_addr);
|
||||
@@ -5547,6 +5741,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
init_completion(&adapter->reset_done);
|
||||
init_completion(&adapter->stats_done);
|
||||
clear_bit(0, &adapter->resetting);
|
||||
adapter->prev_rx_buf_sz = 0;
|
||||
adapter->prev_mtu = 0;
|
||||
|
||||
init_success = false;
|
||||
do {
|
||||
@@ -5647,6 +5843,8 @@ static void ibmvnic_remove(struct vio_dev *dev)
|
||||
unregister_netdevice(netdev);
|
||||
|
||||
release_resources(adapter);
|
||||
release_rx_pools(adapter);
|
||||
release_tx_pools(adapter);
|
||||
release_sub_crqs(adapter, 1);
|
||||
release_crq_queue(adapter);
|
||||
|
||||
|
||||
@@ -827,7 +827,7 @@ struct ibmvnic_rx_buff {
|
||||
|
||||
struct ibmvnic_rx_pool {
|
||||
struct ibmvnic_rx_buff *rx_buff;
|
||||
int size;
|
||||
int size; /* # of buffers in the pool */
|
||||
int index;
|
||||
int buff_size;
|
||||
atomic_t available;
|
||||
@@ -967,6 +967,7 @@ struct ibmvnic_adapter {
|
||||
u64 min_mtu;
|
||||
u64 max_mtu;
|
||||
u64 req_mtu;
|
||||
u64 prev_mtu;
|
||||
u64 max_multicast_filters;
|
||||
u64 vlan_header_insertion;
|
||||
u64 rx_vlan_header_insertion;
|
||||
@@ -979,13 +980,18 @@ struct ibmvnic_adapter {
|
||||
u64 opt_tx_entries_per_subcrq;
|
||||
u64 opt_rxba_entries_per_subcrq;
|
||||
__be64 tx_rx_desc_req;
|
||||
u8 map_id;
|
||||
#define MAX_MAP_ID 255
|
||||
DECLARE_BITMAP(map_ids, MAX_MAP_ID);
|
||||
u32 num_active_rx_scrqs;
|
||||
u32 num_active_rx_pools;
|
||||
u32 num_active_rx_napi;
|
||||
u32 num_active_tx_scrqs;
|
||||
u32 num_active_tx_pools;
|
||||
|
||||
u32 prev_rx_pool_size;
|
||||
u32 prev_tx_pool_size;
|
||||
u32 cur_rx_buf_sz;
|
||||
u32 prev_rx_buf_sz;
|
||||
|
||||
struct tasklet_struct tasklet;
|
||||
enum vnic_state state;
|
||||
|
||||
@@ -96,6 +96,9 @@ struct ltq_etop_priv {
|
||||
struct ltq_etop_chan ch[MAX_DMA_CHAN];
|
||||
int tx_free[MAX_DMA_CHAN >> 1];
|
||||
|
||||
int tx_burst_len;
|
||||
int rx_burst_len;
|
||||
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
@@ -259,7 +262,7 @@ ltq_etop_hw_init(struct net_device *dev)
|
||||
/* enable crc generation */
|
||||
ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG);
|
||||
|
||||
ltq_dma_init_port(DMA_PORT_ETOP);
|
||||
ltq_dma_init_port(DMA_PORT_ETOP, priv->tx_burst_len, rx_burst_len);
|
||||
|
||||
for (i = 0; i < MAX_DMA_CHAN; i++) {
|
||||
int irq = LTQ_DMA_CH0_INT + i;
|
||||
@@ -472,8 +475,8 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
/* dma needs to start on a 16 byte aligned address */
|
||||
byte_offset = CPHYSADDR(skb->data) % 16;
|
||||
/* dma needs to start on a burst length value aligned address */
|
||||
byte_offset = CPHYSADDR(skb->data) % (priv->tx_burst_len * 4);
|
||||
ch->skb[ch->dma.desc] = skb;
|
||||
|
||||
netif_trans_update(dev);
|
||||
@@ -667,6 +670,18 @@ ltq_etop_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&priv->lock);
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
err = device_property_read_u32(&pdev->dev, "lantiq,tx-burst-length", &priv->tx_burst_len);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "unable to read tx-burst-length property\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = device_property_read_u32(&pdev->dev, "lantiq,rx-burst-length", &priv->rx_burst_len);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "unable to read rx-burst-length property\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_DMA_CHAN; i++) {
|
||||
if (IS_TX(i))
|
||||
netif_napi_add(dev, &priv->ch[i].napi,
|
||||
|
||||
@@ -71,6 +71,9 @@ struct xrx200_priv {
|
||||
struct net_device *net_dev;
|
||||
struct device *dev;
|
||||
|
||||
int tx_burst_len;
|
||||
int rx_burst_len;
|
||||
|
||||
__iomem void *pmac_reg;
|
||||
};
|
||||
|
||||
@@ -316,8 +319,8 @@ static netdev_tx_t xrx200_start_xmit(struct sk_buff *skb,
|
||||
if (unlikely(dma_mapping_error(priv->dev, mapping)))
|
||||
goto err_drop;
|
||||
|
||||
/* dma needs to start on a 16 byte aligned address */
|
||||
byte_offset = mapping % 16;
|
||||
/* dma needs to start on a burst length value aligned address */
|
||||
byte_offset = mapping % (priv->tx_burst_len * 4);
|
||||
|
||||
desc->addr = mapping - byte_offset;
|
||||
/* Make sure the address is written before we give it to HW */
|
||||
@@ -369,7 +372,7 @@ static int xrx200_dma_init(struct xrx200_priv *priv)
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
ltq_dma_init_port(DMA_PORT_ETOP);
|
||||
ltq_dma_init_port(DMA_PORT_ETOP, priv->tx_burst_len, rx_burst_len);
|
||||
|
||||
ch_rx->dma.nr = XRX200_DMA_RX;
|
||||
ch_rx->dma.dev = priv->dev;
|
||||
@@ -478,6 +481,18 @@ static int xrx200_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
eth_hw_addr_random(net_dev);
|
||||
|
||||
err = device_property_read_u32(dev, "lantiq,tx-burst-length", &priv->tx_burst_len);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "unable to read tx-burst-length property\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = device_property_read_u32(dev, "lantiq,rx-burst-length", &priv->rx_burst_len);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "unable to read rx-burst-length property\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* bring up the dma engine and IP core */
|
||||
err = xrx200_dma_init(priv);
|
||||
if (err)
|
||||
|
||||
@@ -625,7 +625,6 @@ static int mlx5_devlink_eth_param_register(struct devlink *devlink)
|
||||
devlink_param_driverinit_value_set(devlink,
|
||||
DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH,
|
||||
value);
|
||||
devlink_param_publish(devlink, &enable_eth_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -636,7 +635,6 @@ static void mlx5_devlink_eth_param_unregister(struct devlink *devlink)
|
||||
if (!mlx5_eth_supported(dev))
|
||||
return;
|
||||
|
||||
devlink_param_unpublish(devlink, &enable_eth_param);
|
||||
devlink_param_unregister(devlink, &enable_eth_param);
|
||||
}
|
||||
|
||||
@@ -672,7 +670,6 @@ static int mlx5_devlink_rdma_param_register(struct devlink *devlink)
|
||||
devlink_param_driverinit_value_set(devlink,
|
||||
DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
|
||||
value);
|
||||
devlink_param_publish(devlink, &enable_rdma_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -681,7 +678,6 @@ static void mlx5_devlink_rdma_param_unregister(struct devlink *devlink)
|
||||
if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND))
|
||||
return;
|
||||
|
||||
devlink_param_unpublish(devlink, &enable_rdma_param);
|
||||
devlink_param_unregister(devlink, &enable_rdma_param);
|
||||
}
|
||||
|
||||
@@ -706,7 +702,6 @@ static int mlx5_devlink_vnet_param_register(struct devlink *devlink)
|
||||
devlink_param_driverinit_value_set(devlink,
|
||||
DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,
|
||||
value);
|
||||
devlink_param_publish(devlink, &enable_rdma_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -717,7 +712,6 @@ static void mlx5_devlink_vnet_param_unregister(struct devlink *devlink)
|
||||
if (!mlx5_vnet_supported(dev))
|
||||
return;
|
||||
|
||||
devlink_param_unpublish(devlink, &enable_vnet_param);
|
||||
devlink_param_unregister(devlink, &enable_vnet_param);
|
||||
}
|
||||
|
||||
@@ -808,7 +802,6 @@ int mlx5_devlink_register(struct devlink *devlink)
|
||||
if (err)
|
||||
goto params_reg_err;
|
||||
mlx5_devlink_set_params_init_values(devlink);
|
||||
devlink_params_publish(devlink);
|
||||
|
||||
err = mlx5_devlink_auxdev_params_register(devlink);
|
||||
if (err)
|
||||
@@ -818,6 +811,7 @@ int mlx5_devlink_register(struct devlink *devlink)
|
||||
if (err)
|
||||
goto traps_reg_err;
|
||||
|
||||
devlink_params_publish(devlink);
|
||||
return 0;
|
||||
|
||||
traps_reg_err:
|
||||
@@ -832,9 +826,9 @@ params_reg_err:
|
||||
|
||||
void mlx5_devlink_unregister(struct devlink *devlink)
|
||||
{
|
||||
devlink_params_unpublish(devlink);
|
||||
mlx5_devlink_traps_unregister(devlink);
|
||||
mlx5_devlink_auxdev_params_unregister(devlink);
|
||||
devlink_params_unpublish(devlink);
|
||||
devlink_params_unregister(devlink, mlx5_devlink_params,
|
||||
ARRAY_SIZE(mlx5_devlink_params));
|
||||
devlink_unregister(devlink);
|
||||
|
||||
@@ -90,7 +90,6 @@ struct mlxsw_core {
|
||||
struct devlink_health_reporter *fw_fatal;
|
||||
} health;
|
||||
struct mlxsw_env *env;
|
||||
bool is_initialized; /* Denotes if core was already initialized. */
|
||||
unsigned long driver_priv[];
|
||||
/* driver_priv has to be always the last item */
|
||||
};
|
||||
@@ -1995,12 +1994,6 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
|
||||
if (err)
|
||||
goto err_health_init;
|
||||
|
||||
if (mlxsw_driver->init) {
|
||||
err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack);
|
||||
if (err)
|
||||
goto err_driver_init;
|
||||
}
|
||||
|
||||
err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
|
||||
if (err)
|
||||
goto err_hwmon_init;
|
||||
@@ -2014,7 +2007,12 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
|
||||
if (err)
|
||||
goto err_env_init;
|
||||
|
||||
mlxsw_core->is_initialized = true;
|
||||
if (mlxsw_driver->init) {
|
||||
err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack);
|
||||
if (err)
|
||||
goto err_driver_init;
|
||||
}
|
||||
|
||||
devlink_params_publish(devlink);
|
||||
|
||||
if (!reload)
|
||||
@@ -2022,14 +2020,13 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
|
||||
|
||||
return 0;
|
||||
|
||||
err_driver_init:
|
||||
mlxsw_env_fini(mlxsw_core->env);
|
||||
err_env_init:
|
||||
mlxsw_thermal_fini(mlxsw_core->thermal);
|
||||
err_thermal_init:
|
||||
mlxsw_hwmon_fini(mlxsw_core->hwmon);
|
||||
err_hwmon_init:
|
||||
if (mlxsw_core->driver->fini)
|
||||
mlxsw_core->driver->fini(mlxsw_core);
|
||||
err_driver_init:
|
||||
mlxsw_core_health_fini(mlxsw_core);
|
||||
err_health_init:
|
||||
err_fw_rev_validate:
|
||||
@@ -2100,12 +2097,11 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
|
||||
}
|
||||
|
||||
devlink_params_unpublish(devlink);
|
||||
mlxsw_core->is_initialized = false;
|
||||
if (mlxsw_core->driver->fini)
|
||||
mlxsw_core->driver->fini(mlxsw_core);
|
||||
mlxsw_env_fini(mlxsw_core->env);
|
||||
mlxsw_thermal_fini(mlxsw_core->thermal);
|
||||
mlxsw_hwmon_fini(mlxsw_core->hwmon);
|
||||
if (mlxsw_core->driver->fini)
|
||||
mlxsw_core->driver->fini(mlxsw_core);
|
||||
mlxsw_core_health_fini(mlxsw_core);
|
||||
if (!reload)
|
||||
mlxsw_core_params_unregister(mlxsw_core);
|
||||
@@ -2939,49 +2935,6 @@ struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core)
|
||||
return mlxsw_core->env;
|
||||
}
|
||||
|
||||
bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core)
|
||||
{
|
||||
return mlxsw_core->is_initialized;
|
||||
}
|
||||
|
||||
int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module)
|
||||
{
|
||||
enum mlxsw_reg_pmtm_module_type module_type;
|
||||
char pmtm_pl[MLXSW_REG_PMTM_LEN];
|
||||
int err;
|
||||
|
||||
mlxsw_reg_pmtm_pack(pmtm_pl, module);
|
||||
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
|
||||
if (err)
|
||||
return err;
|
||||
mlxsw_reg_pmtm_unpack(pmtm_pl, &module_type);
|
||||
|
||||
/* Here we need to get the module width according to the module type. */
|
||||
|
||||
switch (module_type) {
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_C2C8X:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_OSFP:
|
||||
return 8;
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_C2C4X:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_QSFP:
|
||||
return 4;
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_C2C2X:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_DSFP:
|
||||
return 2;
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_C2C1X:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X:
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_SFP:
|
||||
return 1;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_core_module_max_width);
|
||||
|
||||
static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
|
||||
@@ -249,8 +249,6 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
|
||||
u8 local_port);
|
||||
bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u8 local_port);
|
||||
struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core);
|
||||
bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core);
|
||||
int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module);
|
||||
|
||||
int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay);
|
||||
bool mlxsw_core_schedule_work(struct work_struct *work);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/sfp.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "core_env.h"
|
||||
@@ -14,12 +15,14 @@
|
||||
struct mlxsw_env_module_info {
|
||||
u64 module_overheat_counter;
|
||||
bool is_overheat;
|
||||
int num_ports_mapped;
|
||||
int num_ports_up;
|
||||
};
|
||||
|
||||
struct mlxsw_env {
|
||||
struct mlxsw_core *core;
|
||||
u8 module_count;
|
||||
spinlock_t module_info_lock; /* Protects 'module_info'. */
|
||||
struct mutex module_info_lock; /* Protects 'module_info'. */
|
||||
struct mlxsw_env_module_info module_info[];
|
||||
};
|
||||
|
||||
@@ -389,6 +392,59 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
|
||||
|
||||
static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module)
|
||||
{
|
||||
char pmaos_pl[MLXSW_REG_PMAOS_LEN];
|
||||
|
||||
mlxsw_reg_pmaos_pack(pmaos_pl, module);
|
||||
mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
|
||||
|
||||
return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
|
||||
}
|
||||
|
||||
int mlxsw_env_reset_module(struct net_device *netdev,
|
||||
struct mlxsw_core *mlxsw_core, u8 module, u32 *flags)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
u32 req = *flags;
|
||||
int err;
|
||||
|
||||
if (!(req & ETH_RESET_PHY) &&
|
||||
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&mlxsw_env->module_info_lock);
|
||||
|
||||
if (mlxsw_env->module_info[module].num_ports_up) {
|
||||
netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mlxsw_env->module_info[module].num_ports_mapped > 1 &&
|
||||
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
|
||||
netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = mlxsw_env_module_reset(mlxsw_core, module);
|
||||
if (err) {
|
||||
netdev_err(netdev, "Failed to reset module\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
|
||||
|
||||
out:
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_reset_module);
|
||||
|
||||
static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
|
||||
u8 module,
|
||||
bool *p_has_temp_sensor)
|
||||
@@ -482,22 +538,32 @@ static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlxsw_env_mtwe_event_func(const struct mlxsw_reg_info *reg,
|
||||
char *mtwe_pl, void *priv)
|
||||
struct mlxsw_env_module_temp_warn_event {
|
||||
struct mlxsw_env *mlxsw_env;
|
||||
char mtwe_pl[MLXSW_REG_MTWE_LEN];
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
static void mlxsw_env_mtwe_event_work(struct work_struct *work)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = priv;
|
||||
struct mlxsw_env_module_temp_warn_event *event;
|
||||
struct mlxsw_env *mlxsw_env;
|
||||
int i, sensor_warning;
|
||||
bool is_overheat;
|
||||
|
||||
event = container_of(work, struct mlxsw_env_module_temp_warn_event,
|
||||
work);
|
||||
mlxsw_env = event->mlxsw_env;
|
||||
|
||||
for (i = 0; i < mlxsw_env->module_count; i++) {
|
||||
/* 64-127 of sensor_index are mapped to the port modules
|
||||
* sequentially (module 0 is mapped to sensor_index 64,
|
||||
* module 1 to sensor_index 65 and so on)
|
||||
*/
|
||||
sensor_warning =
|
||||
mlxsw_reg_mtwe_sensor_warning_get(mtwe_pl,
|
||||
mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
|
||||
i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
|
||||
spin_lock(&mlxsw_env->module_info_lock);
|
||||
mutex_lock(&mlxsw_env->module_info_lock);
|
||||
is_overheat =
|
||||
mlxsw_env->module_info[i].is_overheat;
|
||||
|
||||
@@ -507,13 +573,13 @@ static void mlxsw_env_mtwe_event_func(const struct mlxsw_reg_info *reg,
|
||||
* warning OR current state in "no warning" and MTWE
|
||||
* does not report warning.
|
||||
*/
|
||||
spin_unlock(&mlxsw_env->module_info_lock);
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
continue;
|
||||
} else if (is_overheat && !sensor_warning) {
|
||||
/* MTWE reports "no warning", turn is_overheat off.
|
||||
*/
|
||||
mlxsw_env->module_info[i].is_overheat = false;
|
||||
spin_unlock(&mlxsw_env->module_info_lock);
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
} else {
|
||||
/* Current state is "no warning" and MTWE reports
|
||||
* "warning", increase the counter and turn is_overheat
|
||||
@@ -521,13 +587,32 @@ static void mlxsw_env_mtwe_event_func(const struct mlxsw_reg_info *reg,
|
||||
*/
|
||||
mlxsw_env->module_info[i].is_overheat = true;
|
||||
mlxsw_env->module_info[i].module_overheat_counter++;
|
||||
spin_unlock(&mlxsw_env->module_info_lock);
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(event);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
|
||||
void *priv)
|
||||
{
|
||||
struct mlxsw_env_module_temp_warn_event *event;
|
||||
struct mlxsw_env *mlxsw_env = priv;
|
||||
|
||||
event = kmalloc(sizeof(*event), GFP_ATOMIC);
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
event->mlxsw_env = mlxsw_env;
|
||||
memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN);
|
||||
INIT_WORK(&event->work, mlxsw_env_mtwe_event_work);
|
||||
mlxsw_core_schedule_work(&event->work);
|
||||
}
|
||||
|
||||
static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
|
||||
MLXSW_EVENTL(mlxsw_env_mtwe_event_func, MTWE, MTWE);
|
||||
MLXSW_EVENTL(mlxsw_env_mtwe_listener_func, MTWE, MTWE);
|
||||
|
||||
static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
|
||||
{
|
||||
@@ -568,9 +653,9 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work)
|
||||
work);
|
||||
mlxsw_env = event->mlxsw_env;
|
||||
|
||||
spin_lock_bh(&mlxsw_env->module_info_lock);
|
||||
mutex_lock(&mlxsw_env->module_info_lock);
|
||||
mlxsw_env->module_info[event->module].is_overheat = false;
|
||||
spin_unlock_bh(&mlxsw_env->module_info_lock);
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
|
||||
err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module,
|
||||
&has_temp_sensor);
|
||||
@@ -652,8 +737,10 @@ mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
|
||||
for (i = 0; i < module_count; i++) {
|
||||
char pmaos_pl[MLXSW_REG_PMAOS_LEN];
|
||||
|
||||
mlxsw_reg_pmaos_pack(pmaos_pl, i,
|
||||
MLXSW_REG_PMAOS_E_GENERATE_EVENT);
|
||||
mlxsw_reg_pmaos_pack(pmaos_pl, i);
|
||||
mlxsw_reg_pmaos_e_set(pmaos_pl,
|
||||
MLXSW_REG_PMAOS_E_GENERATE_EVENT);
|
||||
mlxsw_reg_pmaos_ee_set(pmaos_pl, true);
|
||||
err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -667,23 +754,71 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
|
||||
/* Prevent switch driver from accessing uninitialized data. */
|
||||
if (!mlxsw_core_is_initialized(mlxsw_core)) {
|
||||
*p_counter = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_bh(&mlxsw_env->module_info_lock);
|
||||
mutex_lock(&mlxsw_env->module_info_lock);
|
||||
*p_counter = mlxsw_env->module_info[module].module_overheat_counter;
|
||||
spin_unlock_bh(&mlxsw_env->module_info_lock);
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
|
||||
|
||||
void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
|
||||
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
|
||||
return;
|
||||
|
||||
mutex_lock(&mlxsw_env->module_info_lock);
|
||||
mlxsw_env->module_info[module].num_ports_mapped++;
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_module_port_map);
|
||||
|
||||
void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
|
||||
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
|
||||
return;
|
||||
|
||||
mutex_lock(&mlxsw_env->module_info_lock);
|
||||
mlxsw_env->module_info[module].num_ports_mapped--;
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
|
||||
|
||||
int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
|
||||
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&mlxsw_env->module_info_lock);
|
||||
mlxsw_env->module_info[module].num_ports_up++;
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_module_port_up);
|
||||
|
||||
void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
|
||||
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
|
||||
return;
|
||||
|
||||
mutex_lock(&mlxsw_env->module_info_lock);
|
||||
mlxsw_env->module_info[module].num_ports_up--;
|
||||
mutex_unlock(&mlxsw_env->module_info_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_module_port_down);
|
||||
|
||||
int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
|
||||
{
|
||||
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
|
||||
@@ -702,7 +837,7 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
|
||||
if (!env)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&env->module_info_lock);
|
||||
mutex_init(&env->module_info_lock);
|
||||
env->core = mlxsw_core;
|
||||
env->module_count = module_count;
|
||||
*p_env = env;
|
||||
@@ -732,6 +867,7 @@ err_oper_state_event_enable:
|
||||
err_module_plug_event_register:
|
||||
mlxsw_env_temp_warn_event_unregister(env);
|
||||
err_temp_warn_event_register:
|
||||
mutex_destroy(&env->module_info_lock);
|
||||
kfree(env);
|
||||
return err;
|
||||
}
|
||||
@@ -742,5 +878,6 @@ void mlxsw_env_fini(struct mlxsw_env *env)
|
||||
/* Make sure there is no more event work scheduled. */
|
||||
mlxsw_core_flush_owq();
|
||||
mlxsw_env_temp_warn_event_unregister(env);
|
||||
mutex_destroy(&env->module_info_lock);
|
||||
kfree(env);
|
||||
}
|
||||
|
||||
@@ -24,9 +24,22 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
|
||||
const struct ethtool_module_eeprom *page,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
int mlxsw_env_reset_module(struct net_device *netdev,
|
||||
struct mlxsw_core *mlxsw_core, u8 module,
|
||||
u32 *flags);
|
||||
|
||||
int
|
||||
mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
|
||||
u64 *p_counter);
|
||||
|
||||
void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module);
|
||||
|
||||
void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module);
|
||||
|
||||
int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module);
|
||||
|
||||
void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module);
|
||||
|
||||
int mlxsw_env_init(struct mlxsw_core *core, struct mlxsw_env **p_env);
|
||||
void mlxsw_env_fini(struct mlxsw_env *env);
|
||||
|
||||
|
||||
@@ -54,8 +54,20 @@ static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_m_port_dummy_open_stop(struct net_device *dev)
|
||||
static int mlxsw_m_port_open(struct net_device *dev)
|
||||
{
|
||||
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
|
||||
struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
|
||||
|
||||
return mlxsw_env_module_port_up(mlxsw_m->core, mlxsw_m_port->module);
|
||||
}
|
||||
|
||||
static int mlxsw_m_port_stop(struct net_device *dev)
|
||||
{
|
||||
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
|
||||
struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
|
||||
|
||||
mlxsw_env_module_port_down(mlxsw_m->core, mlxsw_m_port->module);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -70,8 +82,8 @@ mlxsw_m_port_get_devlink_port(struct net_device *dev)
|
||||
}
|
||||
|
||||
static const struct net_device_ops mlxsw_m_port_netdev_ops = {
|
||||
.ndo_open = mlxsw_m_port_dummy_open_stop,
|
||||
.ndo_stop = mlxsw_m_port_dummy_open_stop,
|
||||
.ndo_open = mlxsw_m_port_open,
|
||||
.ndo_stop = mlxsw_m_port_stop,
|
||||
.ndo_get_devlink_port = mlxsw_m_port_get_devlink_port,
|
||||
};
|
||||
|
||||
@@ -124,11 +136,21 @@ mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev,
|
||||
page, extack);
|
||||
}
|
||||
|
||||
static int mlxsw_m_reset(struct net_device *netdev, u32 *flags)
|
||||
{
|
||||
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
|
||||
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
|
||||
|
||||
return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->module,
|
||||
flags);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
|
||||
.get_drvinfo = mlxsw_m_module_get_drvinfo,
|
||||
.get_module_info = mlxsw_m_get_module_info,
|
||||
.get_module_eeprom = mlxsw_m_get_module_eeprom,
|
||||
.get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
|
||||
.reset = mlxsw_m_reset,
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -266,6 +288,7 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
|
||||
|
||||
if (WARN_ON_ONCE(module >= max_ports))
|
||||
return -EINVAL;
|
||||
mlxsw_env_module_port_map(mlxsw_m->core, module);
|
||||
mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports;
|
||||
|
||||
return 0;
|
||||
@@ -274,6 +297,7 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
|
||||
static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module)
|
||||
{
|
||||
mlxsw_m->module_to_port[module] = -1;
|
||||
mlxsw_env_module_port_unmap(mlxsw_m->core, module);
|
||||
}
|
||||
|
||||
static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
|
||||
|
||||
@@ -5681,6 +5681,14 @@ static inline void mlxsw_reg_pspa_pack(char *payload, u8 swid, u8 local_port)
|
||||
|
||||
MLXSW_REG_DEFINE(pmaos, MLXSW_REG_PMAOS_ID, MLXSW_REG_PMAOS_LEN);
|
||||
|
||||
/* reg_pmaos_rst
|
||||
* Module reset toggle.
|
||||
* Note: Setting reset while module is plugged-in will result in transition to
|
||||
* "initializing" operational state.
|
||||
* Access: OP
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, rst, 0x00, 31, 1);
|
||||
|
||||
/* reg_pmaos_slot_index
|
||||
* Slot index.
|
||||
* Access: Index
|
||||
@@ -5693,6 +5701,24 @@ MLXSW_ITEM32(reg, pmaos, slot_index, 0x00, 24, 4);
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, module, 0x00, 16, 8);
|
||||
|
||||
enum mlxsw_reg_pmaos_admin_status {
|
||||
MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED = 1,
|
||||
MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED = 2,
|
||||
/* If the module is active and then unplugged, or experienced an error
|
||||
* event, the operational status should go to "disabled" and can only
|
||||
* be enabled upon explicit enable command.
|
||||
*/
|
||||
MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED_ONCE = 3,
|
||||
};
|
||||
|
||||
/* reg_pmaos_admin_status
|
||||
* Module administrative state (the desired state of the module).
|
||||
* Note: To disable a module, all ports associated with the port must be
|
||||
* administatively down first.
|
||||
* Access: RW
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, admin_status, 0x00, 8, 4);
|
||||
|
||||
/* reg_pmaos_ase
|
||||
* Admin state update enable.
|
||||
* If this bit is set, admin state will be updated based on admin_state field.
|
||||
@@ -5721,13 +5747,10 @@ enum mlxsw_reg_pmaos_e {
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, e, 0x04, 0, 2);
|
||||
|
||||
static inline void mlxsw_reg_pmaos_pack(char *payload, u8 module,
|
||||
enum mlxsw_reg_pmaos_e e)
|
||||
static inline void mlxsw_reg_pmaos_pack(char *payload, u8 module)
|
||||
{
|
||||
MLXSW_REG_ZERO(pmaos, payload);
|
||||
mlxsw_reg_pmaos_module_set(payload, module);
|
||||
mlxsw_reg_pmaos_e_set(payload, e);
|
||||
mlxsw_reg_pmaos_ee_set(payload, true);
|
||||
}
|
||||
|
||||
/* PPLR - Port Physical Loopback Register
|
||||
@@ -5766,6 +5789,69 @@ static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port,
|
||||
MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0);
|
||||
}
|
||||
|
||||
/* PMTDB - Port Module To local DataBase Register
|
||||
* ----------------------------------------------
|
||||
* The PMTDB register allows to query the possible module<->local port
|
||||
* mapping than can be used in PMLP. It does not represent the actual/current
|
||||
* mapping of the local to module. Actual mapping is only defined by PMLP.
|
||||
*/
|
||||
#define MLXSW_REG_PMTDB_ID 0x501A
|
||||
#define MLXSW_REG_PMTDB_LEN 0x40
|
||||
|
||||
MLXSW_REG_DEFINE(pmtdb, MLXSW_REG_PMTDB_ID, MLXSW_REG_PMTDB_LEN);
|
||||
|
||||
/* reg_pmtdb_slot_index
|
||||
* Slot index (0: Main board).
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmtdb, slot_index, 0x00, 24, 4);
|
||||
|
||||
/* reg_pmtdb_module
|
||||
* Module number.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmtdb, module, 0x00, 16, 8);
|
||||
|
||||
/* reg_pmtdb_ports_width
|
||||
* Port's width
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmtdb, ports_width, 0x00, 12, 4);
|
||||
|
||||
/* reg_pmtdb_num_ports
|
||||
* Number of ports in a single module (split/breakout)
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmtdb, num_ports, 0x00, 8, 4);
|
||||
|
||||
enum mlxsw_reg_pmtdb_status {
|
||||
MLXSW_REG_PMTDB_STATUS_SUCCESS,
|
||||
};
|
||||
|
||||
/* reg_pmtdb_status
|
||||
* Status
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmtdb, status, 0x00, 0, 4);
|
||||
|
||||
/* reg_pmtdb_port_num
|
||||
* The local_port value which can be assigned to the module.
|
||||
* In case of more than one port, port<x> represent the /<x> port of
|
||||
* the module.
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM16_INDEXED(reg, pmtdb, port_num, 0x04, 0, 8, 0x02, 0x00, false);
|
||||
|
||||
static inline void mlxsw_reg_pmtdb_pack(char *payload, u8 slot_index, u8 module,
|
||||
u8 ports_width, u8 num_ports)
|
||||
{
|
||||
MLXSW_REG_ZERO(pmtdb, payload);
|
||||
mlxsw_reg_pmtdb_slot_index_set(payload, slot_index);
|
||||
mlxsw_reg_pmtdb_module_set(payload, module);
|
||||
mlxsw_reg_pmtdb_ports_width_set(payload, ports_width);
|
||||
mlxsw_reg_pmtdb_num_ports_set(payload, num_ports);
|
||||
}
|
||||
|
||||
/* PMPE - Port Module Plug/Unplug Event Register
|
||||
* ---------------------------------------------
|
||||
* This register reports any operational status change of a module.
|
||||
@@ -5860,67 +5946,51 @@ static inline void mlxsw_reg_pddr_pack(char *payload, u8 local_port,
|
||||
mlxsw_reg_pddr_page_select_set(payload, page_select);
|
||||
}
|
||||
|
||||
/* PMTM - Port Module Type Mapping Register
|
||||
* ----------------------------------------
|
||||
* The PMTM allows query or configuration of module types.
|
||||
/* PLLP - Port Local port to Label Port mapping Register
|
||||
* -----------------------------------------------------
|
||||
* The PLLP register returns the mapping from Local Port into Label Port.
|
||||
*/
|
||||
#define MLXSW_REG_PMTM_ID 0x5067
|
||||
#define MLXSW_REG_PMTM_LEN 0x10
|
||||
#define MLXSW_REG_PLLP_ID 0x504A
|
||||
#define MLXSW_REG_PLLP_LEN 0x10
|
||||
|
||||
MLXSW_REG_DEFINE(pmtm, MLXSW_REG_PMTM_ID, MLXSW_REG_PMTM_LEN);
|
||||
MLXSW_REG_DEFINE(pllp, MLXSW_REG_PLLP_ID, MLXSW_REG_PLLP_LEN);
|
||||
|
||||
/* reg_pmtm_module
|
||||
* Module number.
|
||||
/* reg_pllp_local_port
|
||||
* Local port number.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmtm, module, 0x00, 16, 8);
|
||||
MLXSW_ITEM32(reg, pllp, local_port, 0x00, 16, 8);
|
||||
|
||||
enum mlxsw_reg_pmtm_module_type {
|
||||
/* Backplane with 4 lanes */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_BP_4X,
|
||||
/* QSFP */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_QSFP,
|
||||
/* SFP */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_SFP,
|
||||
/* Backplane with single lane */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_BP_1X = 4,
|
||||
/* Backplane with two lane */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_BP_2X = 8,
|
||||
/* Chip2Chip4x */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_C2C4X = 10,
|
||||
/* Chip2Chip2x */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_C2C2X,
|
||||
/* Chip2Chip1x */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_C2C1X,
|
||||
/* QSFP-DD */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD = 14,
|
||||
/* OSFP */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_OSFP,
|
||||
/* SFP-DD */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD,
|
||||
/* DSFP */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_DSFP,
|
||||
/* Chip2Chip8x */
|
||||
MLXSW_REG_PMTM_MODULE_TYPE_C2C8X,
|
||||
};
|
||||
|
||||
/* reg_pmtm_module_type
|
||||
* Module type.
|
||||
* Access: RW
|
||||
/* reg_pllp_label_port
|
||||
* Front panel label of the port.
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmtm, module_type, 0x04, 0, 4);
|
||||
MLXSW_ITEM32(reg, pllp, label_port, 0x00, 0, 8);
|
||||
|
||||
static inline void mlxsw_reg_pmtm_pack(char *payload, u8 module)
|
||||
/* reg_pllp_split_num
|
||||
* Label split mapping for local_port.
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pllp, split_num, 0x04, 0, 4);
|
||||
|
||||
/* reg_pllp_slot_index
|
||||
* Slot index (0: Main board).
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pllp, slot_index, 0x08, 0, 4);
|
||||
|
||||
static inline void mlxsw_reg_pllp_pack(char *payload, u8 local_port)
|
||||
{
|
||||
MLXSW_REG_ZERO(pmtm, payload);
|
||||
mlxsw_reg_pmtm_module_set(payload, module);
|
||||
MLXSW_REG_ZERO(pllp, payload);
|
||||
mlxsw_reg_pllp_local_port_set(payload, local_port);
|
||||
}
|
||||
|
||||
static inline void
|
||||
mlxsw_reg_pmtm_unpack(char *payload,
|
||||
enum mlxsw_reg_pmtm_module_type *module_type)
|
||||
static inline void mlxsw_reg_pllp_unpack(char *payload, u8 *label_port,
|
||||
u8 *split_num, u8 *slot_index)
|
||||
{
|
||||
*module_type = mlxsw_reg_pmtm_module_type_get(payload);
|
||||
*label_port = mlxsw_reg_pllp_label_port_get(payload);
|
||||
*split_num = mlxsw_reg_pllp_split_num_get(payload);
|
||||
*slot_index = mlxsw_reg_pllp_slot_index_get(payload);
|
||||
}
|
||||
|
||||
/* HTGT - Host Trap Group Table
|
||||
@@ -12200,9 +12270,10 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
|
||||
MLXSW_REG(pspa),
|
||||
MLXSW_REG(pmaos),
|
||||
MLXSW_REG(pplr),
|
||||
MLXSW_REG(pmtdb),
|
||||
MLXSW_REG(pmpe),
|
||||
MLXSW_REG(pddr),
|
||||
MLXSW_REG(pmtm),
|
||||
MLXSW_REG(pllp),
|
||||
MLXSW_REG(htgt),
|
||||
MLXSW_REG(hpkt),
|
||||
MLXSW_REG(rgcr),
|
||||
|
||||
@@ -25,9 +25,6 @@ enum mlxsw_res_id {
|
||||
MLXSW_RES_ID_MAX_SYSTEM_PORT,
|
||||
MLXSW_RES_ID_MAX_LAG,
|
||||
MLXSW_RES_ID_MAX_LAG_MEMBERS,
|
||||
MLXSW_RES_ID_LOCAL_PORTS_IN_1X,
|
||||
MLXSW_RES_ID_LOCAL_PORTS_IN_2X,
|
||||
MLXSW_RES_ID_LOCAL_PORTS_IN_4X,
|
||||
MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER,
|
||||
MLXSW_RES_ID_CELL_SIZE,
|
||||
MLXSW_RES_ID_MAX_HEADROOM_SIZE,
|
||||
@@ -84,9 +81,6 @@ static u16 mlxsw_res_ids[] = {
|
||||
[MLXSW_RES_ID_MAX_SYSTEM_PORT] = 0x2502,
|
||||
[MLXSW_RES_ID_MAX_LAG] = 0x2520,
|
||||
[MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521,
|
||||
[MLXSW_RES_ID_LOCAL_PORTS_IN_1X] = 0x2610,
|
||||
[MLXSW_RES_ID_LOCAL_PORTS_IN_2X] = 0x2611,
|
||||
[MLXSW_RES_ID_LOCAL_PORTS_IN_4X] = 0x2612,
|
||||
[MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */
|
||||
[MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */
|
||||
[MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
#define MLXSW_SP1_FWREV_MAJOR 13
|
||||
#define MLXSW_SP1_FWREV_MINOR 2008
|
||||
#define MLXSW_SP1_FWREV_SUBMINOR 2406
|
||||
#define MLXSW_SP1_FWREV_SUBMINOR 3326
|
||||
#define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702
|
||||
|
||||
static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = {
|
||||
@@ -64,7 +64,7 @@ static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = {
|
||||
|
||||
#define MLXSW_SP2_FWREV_MAJOR 29
|
||||
#define MLXSW_SP2_FWREV_MINOR 2008
|
||||
#define MLXSW_SP2_FWREV_SUBMINOR 2406
|
||||
#define MLXSW_SP2_FWREV_SUBMINOR 3326
|
||||
|
||||
static const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = {
|
||||
.major = MLXSW_SP2_FWREV_MAJOR,
|
||||
@@ -79,7 +79,7 @@ static const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = {
|
||||
|
||||
#define MLXSW_SP3_FWREV_MAJOR 30
|
||||
#define MLXSW_SP3_FWREV_MINOR 2008
|
||||
#define MLXSW_SP3_FWREV_SUBMINOR 2406
|
||||
#define MLXSW_SP3_FWREV_SUBMINOR 3326
|
||||
|
||||
static const struct mlxsw_fw_rev mlxsw_sp3_fw_rev = {
|
||||
.major = MLXSW_SP3_FWREV_MAJOR,
|
||||
@@ -351,12 +351,12 @@ static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid)
|
||||
static int mlxsw_sp_port_swid_set(struct mlxsw_sp *mlxsw_sp,
|
||||
u8 local_port, u8 swid)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
char pspa_pl[MLXSW_REG_PSPA_LEN];
|
||||
|
||||
mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sp_port->local_port);
|
||||
mlxsw_reg_pspa_pack(pspa_pl, swid, local_port);
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl);
|
||||
}
|
||||
|
||||
@@ -529,55 +529,80 @@ mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
|
||||
port_mapping->module = module;
|
||||
port_mapping->width = width;
|
||||
port_mapping->module_width = width;
|
||||
port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
static int
|
||||
mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
const struct mlxsw_sp_port_mapping *port_mapping)
|
||||
{
|
||||
struct mlxsw_sp_port_mapping *port_mapping = &mlxsw_sp_port->mapping;
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
char pmlp_pl[MLXSW_REG_PMLP_LEN];
|
||||
int i;
|
||||
int i, err;
|
||||
|
||||
mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port);
|
||||
mlxsw_env_module_port_map(mlxsw_sp->core, port_mapping->module);
|
||||
|
||||
mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
|
||||
mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width);
|
||||
for (i = 0; i < port_mapping->width; i++) {
|
||||
mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module);
|
||||
mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */
|
||||
}
|
||||
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
|
||||
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
|
||||
if (err)
|
||||
goto err_pmlp_write;
|
||||
return 0;
|
||||
|
||||
err_pmlp_write:
|
||||
mlxsw_env_module_port_unmap(mlxsw_sp->core, port_mapping->module);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_module_unmap(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
static void mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
u8 module)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
char pmlp_pl[MLXSW_REG_PMLP_LEN];
|
||||
|
||||
mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port);
|
||||
mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
|
||||
mlxsw_reg_pmlp_width_set(pmlp_pl, 0);
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
|
||||
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
|
||||
mlxsw_env_module_port_unmap(mlxsw_sp->core, module);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_open(struct net_device *dev)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
int err;
|
||||
|
||||
err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
|
||||
err = mlxsw_env_module_port_up(mlxsw_sp->core,
|
||||
mlxsw_sp_port->mapping.module);
|
||||
if (err)
|
||||
return err;
|
||||
err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
|
||||
if (err)
|
||||
goto err_port_admin_status_set;
|
||||
netif_start_queue(dev);
|
||||
return 0;
|
||||
|
||||
err_port_admin_status_set:
|
||||
mlxsw_env_module_port_down(mlxsw_sp->core,
|
||||
mlxsw_sp_port->mapping.module);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_stop(struct net_device *dev)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
return mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
|
||||
mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
|
||||
mlxsw_env_module_port_down(mlxsw_sp->core,
|
||||
mlxsw_sp_port->mapping.module);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,
|
||||
@@ -1442,29 +1467,68 @@ mlxsw_sp_port_vlan_classification_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvc), spvc_pl);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_label_info_get(struct mlxsw_sp *mlxsw_sp,
|
||||
u8 local_port, u8 *port_number,
|
||||
u8 *split_port_subnumber,
|
||||
u8 *slot_index)
|
||||
{
|
||||
char pllp_pl[MLXSW_REG_PLLP_LEN];
|
||||
int err;
|
||||
|
||||
mlxsw_reg_pllp_pack(pllp_pl, local_port);
|
||||
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pllp), pllp_pl);
|
||||
if (err)
|
||||
return err;
|
||||
mlxsw_reg_pllp_unpack(pllp_pl, port_number,
|
||||
split_port_subnumber, slot_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
u8 split_base_local_port,
|
||||
bool split,
|
||||
struct mlxsw_sp_port_mapping *port_mapping)
|
||||
{
|
||||
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
|
||||
bool split = !!split_base_local_port;
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
u32 lanes = port_mapping->width;
|
||||
u8 split_port_subnumber;
|
||||
struct net_device *dev;
|
||||
u8 port_number;
|
||||
u8 slot_index;
|
||||
bool splittable;
|
||||
int err;
|
||||
|
||||
err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, port_mapping);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n",
|
||||
local_port);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_port_swid_set(mlxsw_sp, local_port, 0);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n",
|
||||
local_port);
|
||||
goto err_port_swid_set;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_port_label_info_get(mlxsw_sp, local_port, &port_number,
|
||||
&split_port_subnumber, &slot_index);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get port label information\n",
|
||||
local_port);
|
||||
goto err_port_label_info_get;
|
||||
}
|
||||
|
||||
splittable = lanes > 1 && !split;
|
||||
err = mlxsw_core_port_init(mlxsw_sp->core, local_port,
|
||||
port_mapping->module + 1, split,
|
||||
port_mapping->lane / lanes,
|
||||
splittable, lanes,
|
||||
mlxsw_sp->base_mac,
|
||||
port_number, split, split_port_subnumber,
|
||||
splittable, lanes, mlxsw_sp->base_mac,
|
||||
sizeof(mlxsw_sp->base_mac));
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n",
|
||||
local_port);
|
||||
return err;
|
||||
goto err_core_port_init;
|
||||
}
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct mlxsw_sp_port));
|
||||
@@ -1480,7 +1544,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
mlxsw_sp_port->local_port = local_port;
|
||||
mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID;
|
||||
mlxsw_sp_port->split = split;
|
||||
mlxsw_sp_port->split_base_local_port = split_base_local_port;
|
||||
mlxsw_sp_port->mapping = *port_mapping;
|
||||
mlxsw_sp_port->link.autoneg = 1;
|
||||
INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list);
|
||||
@@ -1498,20 +1561,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
dev->netdev_ops = &mlxsw_sp_port_netdev_ops;
|
||||
dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops;
|
||||
|
||||
err = mlxsw_sp_port_module_map(mlxsw_sp_port);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n",
|
||||
mlxsw_sp_port->local_port);
|
||||
goto err_port_module_map;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_port_swid_set(mlxsw_sp_port, 0);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n",
|
||||
mlxsw_sp_port->local_port);
|
||||
goto err_port_swid_set;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_port_dev_addr_init(mlxsw_sp_port);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unable to init port mac address\n",
|
||||
@@ -1712,21 +1761,24 @@ err_max_speed_get:
|
||||
err_port_speed_by_width_set:
|
||||
err_port_system_port_mapping_set:
|
||||
err_dev_addr_init:
|
||||
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
|
||||
err_port_swid_set:
|
||||
mlxsw_sp_port_module_unmap(mlxsw_sp_port);
|
||||
err_port_module_map:
|
||||
free_percpu(mlxsw_sp_port->pcpu_stats);
|
||||
err_alloc_stats:
|
||||
free_netdev(dev);
|
||||
err_alloc_etherdev:
|
||||
mlxsw_core_port_fini(mlxsw_sp->core, local_port);
|
||||
err_core_port_init:
|
||||
err_port_label_info_get:
|
||||
mlxsw_sp_port_swid_set(mlxsw_sp, local_port,
|
||||
MLXSW_PORT_SWID_DISABLED_PORT);
|
||||
err_port_swid_set:
|
||||
mlxsw_sp_port_module_unmap(mlxsw_sp, local_port, port_mapping->module);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
|
||||
u8 module = mlxsw_sp_port->mapping.module;
|
||||
|
||||
cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);
|
||||
cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw);
|
||||
@@ -1742,12 +1794,13 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
|
||||
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
|
||||
mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);
|
||||
mlxsw_sp_port_buffers_fini(mlxsw_sp_port);
|
||||
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
|
||||
mlxsw_sp_port_module_unmap(mlxsw_sp_port);
|
||||
free_percpu(mlxsw_sp_port->pcpu_stats);
|
||||
WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list));
|
||||
free_netdev(mlxsw_sp_port->dev);
|
||||
mlxsw_core_port_fini(mlxsw_sp->core, local_port);
|
||||
mlxsw_sp_port_swid_set(mlxsw_sp, local_port,
|
||||
MLXSW_PORT_SWID_DISABLED_PORT);
|
||||
mlxsw_sp_port_module_unmap(mlxsw_sp, local_port, module);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)
|
||||
@@ -1789,8 +1842,15 @@ static void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp)
|
||||
kfree(mlxsw_sp_port);
|
||||
}
|
||||
|
||||
static bool mlxsw_sp_local_port_valid(u8 local_port)
|
||||
{
|
||||
return local_port != MLXSW_PORT_CPU_PORT;
|
||||
}
|
||||
|
||||
static bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u8 local_port)
|
||||
{
|
||||
if (!mlxsw_sp_local_port_valid(local_port))
|
||||
return false;
|
||||
return mlxsw_sp->ports[local_port] != NULL;
|
||||
}
|
||||
|
||||
@@ -1827,7 +1887,7 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
|
||||
port_mapping = mlxsw_sp->port_mapping[i];
|
||||
if (!port_mapping)
|
||||
continue;
|
||||
err = mlxsw_sp_port_create(mlxsw_sp, i, 0, port_mapping);
|
||||
err = mlxsw_sp_port_create(mlxsw_sp, i, false, port_mapping);
|
||||
if (err)
|
||||
goto err_port_create;
|
||||
}
|
||||
@@ -1894,17 +1954,10 @@ static void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp)
|
||||
kfree(mlxsw_sp->port_mapping);
|
||||
}
|
||||
|
||||
static u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width)
|
||||
{
|
||||
u8 offset = (local_port - 1) % max_width;
|
||||
|
||||
return local_port - offset;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
|
||||
mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_port_mapping *port_mapping,
|
||||
unsigned int count, u8 offset)
|
||||
unsigned int count, const char *pmtdb_pl)
|
||||
{
|
||||
struct mlxsw_sp_port_mapping split_port_mapping;
|
||||
int err, i;
|
||||
@@ -1912,8 +1965,13 @@ mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
|
||||
split_port_mapping = *port_mapping;
|
||||
split_port_mapping.width /= count;
|
||||
for (i = 0; i < count; i++) {
|
||||
err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * offset,
|
||||
base_port, &split_port_mapping);
|
||||
u8 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
|
||||
|
||||
if (!mlxsw_sp_local_port_valid(s_local_port))
|
||||
continue;
|
||||
|
||||
err = mlxsw_sp_port_create(mlxsw_sp, s_local_port,
|
||||
true, &split_port_mapping);
|
||||
if (err)
|
||||
goto err_port_create;
|
||||
split_port_mapping.lane += split_port_mapping.width;
|
||||
@@ -1922,49 +1980,34 @@ mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
|
||||
return 0;
|
||||
|
||||
err_port_create:
|
||||
for (i--; i >= 0; i--)
|
||||
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
|
||||
mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
|
||||
for (i--; i >= 0; i--) {
|
||||
u8 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
|
||||
|
||||
if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
|
||||
mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp,
|
||||
u8 base_port,
|
||||
unsigned int count, u8 offset)
|
||||
unsigned int count,
|
||||
const char *pmtdb_pl)
|
||||
{
|
||||
struct mlxsw_sp_port_mapping *port_mapping;
|
||||
int i;
|
||||
|
||||
/* Go over original unsplit ports in the gap and recreate them. */
|
||||
for (i = 0; i < count * offset; i++) {
|
||||
port_mapping = mlxsw_sp->port_mapping[base_port + i];
|
||||
if (!port_mapping)
|
||||
for (i = 0; i < count; i++) {
|
||||
u8 local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
|
||||
|
||||
port_mapping = mlxsw_sp->port_mapping[local_port];
|
||||
if (!port_mapping || !mlxsw_sp_local_port_valid(local_port))
|
||||
continue;
|
||||
mlxsw_sp_port_create(mlxsw_sp, base_port + i, 0, port_mapping);
|
||||
mlxsw_sp_port_create(mlxsw_sp, local_port,
|
||||
false, port_mapping);
|
||||
}
|
||||
}
|
||||
|
||||
static int mlxsw_sp_local_ports_offset(struct mlxsw_core *mlxsw_core,
|
||||
unsigned int count,
|
||||
unsigned int max_width)
|
||||
{
|
||||
enum mlxsw_res_id local_ports_in_x_res_id;
|
||||
int split_width = max_width / count;
|
||||
|
||||
if (split_width == 1)
|
||||
local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_1X;
|
||||
else if (split_width == 2)
|
||||
local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_2X;
|
||||
else if (split_width == 4)
|
||||
local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_4X;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (!mlxsw_core_res_valid(mlxsw_core, local_ports_in_x_res_id))
|
||||
return -EINVAL;
|
||||
return mlxsw_core_res_get(mlxsw_core, local_ports_in_x_res_id);
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_port *
|
||||
mlxsw_sp_port_get_by_local_port(struct mlxsw_sp *mlxsw_sp, u8 local_port)
|
||||
{
|
||||
@@ -1980,9 +2023,8 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
|
||||
struct mlxsw_sp_port_mapping port_mapping;
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
int max_width;
|
||||
u8 base_port;
|
||||
int offset;
|
||||
enum mlxsw_reg_pmtdb_status status;
|
||||
char pmtdb_pl[MLXSW_REG_PMTDB_LEN];
|
||||
int i;
|
||||
int err;
|
||||
|
||||
@@ -1994,57 +2036,37 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
max_width = mlxsw_core_module_max_width(mlxsw_core,
|
||||
mlxsw_sp_port->mapping.module);
|
||||
if (max_width < 0) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module");
|
||||
return max_width;
|
||||
}
|
||||
|
||||
/* Split port with non-max cannot be split. */
|
||||
if (mlxsw_sp_port->mapping.width != max_width) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Port cannot be split\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Port cannot be split");
|
||||
if (mlxsw_sp_port->split) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Port is already split");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width);
|
||||
if (offset < 0) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset");
|
||||
return -EINVAL;
|
||||
mlxsw_reg_pmtdb_pack(pmtdb_pl, 0, mlxsw_sp_port->mapping.module,
|
||||
mlxsw_sp_port->mapping.module_width / count,
|
||||
count);
|
||||
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Failed to query split info");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Only in case max split is being done, the local port and
|
||||
* base port may differ.
|
||||
*/
|
||||
base_port = count == max_width ?
|
||||
mlxsw_sp_cluster_base_port_get(local_port, max_width) :
|
||||
local_port;
|
||||
|
||||
for (i = 0; i < count * offset; i++) {
|
||||
/* Expect base port to exist and also the one in the middle in
|
||||
* case of maximal split count.
|
||||
*/
|
||||
if (i == 0 || (count == max_width && i == count / 2))
|
||||
continue;
|
||||
|
||||
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i)) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration");
|
||||
return -EINVAL;
|
||||
}
|
||||
status = mlxsw_reg_pmtdb_status_get(pmtdb_pl);
|
||||
if (status != MLXSW_REG_PMTDB_STATUS_SUCCESS) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unsupported split configuration");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port_mapping = mlxsw_sp_port->mapping;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
|
||||
mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
|
||||
for (i = 0; i < count; i++) {
|
||||
u8 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
|
||||
|
||||
err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, &port_mapping,
|
||||
count, offset);
|
||||
if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
|
||||
mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
|
||||
}
|
||||
|
||||
err = mlxsw_sp_port_split_create(mlxsw_sp, &port_mapping,
|
||||
count, pmtdb_pl);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n");
|
||||
goto err_port_split_create;
|
||||
@@ -2053,7 +2075,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
||||
return 0;
|
||||
|
||||
err_port_split_create:
|
||||
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset);
|
||||
mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -2062,11 +2084,10 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
char pmtdb_pl[MLXSW_REG_PMTDB_LEN];
|
||||
unsigned int count;
|
||||
int max_width;
|
||||
u8 base_port;
|
||||
int offset;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);
|
||||
if (!mlxsw_sp_port) {
|
||||
@@ -2077,35 +2098,30 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
|
||||
}
|
||||
|
||||
if (!mlxsw_sp_port->split) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Port was not split\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Port was not split");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
max_width = mlxsw_core_module_max_width(mlxsw_core,
|
||||
mlxsw_sp_port->mapping.module);
|
||||
if (max_width < 0) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module");
|
||||
return max_width;
|
||||
count = mlxsw_sp_port->mapping.module_width /
|
||||
mlxsw_sp_port->mapping.width;
|
||||
|
||||
mlxsw_reg_pmtdb_pack(pmtdb_pl, 0, mlxsw_sp_port->mapping.module,
|
||||
mlxsw_sp_port->mapping.module_width / count,
|
||||
count);
|
||||
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Failed to query split info");
|
||||
return err;
|
||||
}
|
||||
|
||||
count = max_width / mlxsw_sp_port->mapping.width;
|
||||
for (i = 0; i < count; i++) {
|
||||
u8 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
|
||||
|
||||
offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width);
|
||||
if (WARN_ON(offset < 0)) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset");
|
||||
return -EINVAL;
|
||||
if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
|
||||
mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
|
||||
}
|
||||
|
||||
base_port = mlxsw_sp_port->split_base_local_port;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
|
||||
mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
|
||||
|
||||
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset);
|
||||
mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -144,7 +144,8 @@ struct mlxsw_sp_mall_entry;
|
||||
|
||||
struct mlxsw_sp_port_mapping {
|
||||
u8 module;
|
||||
u8 width;
|
||||
u8 width; /* Number of lanes used by the port */
|
||||
u8 module_width; /* Number of lanes in the module (static) */
|
||||
u8 lane;
|
||||
};
|
||||
|
||||
@@ -345,7 +346,6 @@ struct mlxsw_sp_port {
|
||||
u16 egr_types;
|
||||
struct mlxsw_sp_ptp_port_stats stats;
|
||||
} ptp;
|
||||
u8 split_base_local_port;
|
||||
int max_mtu;
|
||||
u32 max_speed;
|
||||
struct mlxsw_sp_hdroom *hdroom;
|
||||
|
||||
@@ -1197,6 +1197,15 @@ mlxsw_sp_get_rmon_stats(struct net_device *dev,
|
||||
*ranges = mlxsw_rmon_ranges;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_reset(struct net_device *dev, u32 *flags)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
u8 module = mlxsw_sp_port->mapping.module;
|
||||
|
||||
return mlxsw_env_reset_module(dev, mlxsw_sp->core, module, flags);
|
||||
}
|
||||
|
||||
const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
|
||||
.cap_link_lanes_supported = true,
|
||||
.get_drvinfo = mlxsw_sp_port_get_drvinfo,
|
||||
@@ -1218,6 +1227,7 @@ const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
|
||||
.get_eth_mac_stats = mlxsw_sp_get_eth_mac_stats,
|
||||
.get_eth_ctrl_stats = mlxsw_sp_get_eth_ctrl_stats,
|
||||
.get_rmon_stats = mlxsw_sp_get_rmon_stats,
|
||||
.reset = mlxsw_sp_reset,
|
||||
};
|
||||
|
||||
struct mlxsw_sp1_port_link_mode {
|
||||
|
||||
@@ -499,8 +499,7 @@ struct nfp_reprs *nfp_reprs_alloc(unsigned int num_reprs)
|
||||
{
|
||||
struct nfp_reprs *reprs;
|
||||
|
||||
reprs = kzalloc(sizeof(*reprs) +
|
||||
num_reprs * sizeof(struct net_device *), GFP_KERNEL);
|
||||
reprs = kzalloc(struct_size(reprs, reprs, num_reprs), GFP_KERNEL);
|
||||
if (!reprs)
|
||||
return NULL;
|
||||
reprs->num_reprs = num_reprs;
|
||||
|
||||
@@ -2763,25 +2763,6 @@ static int qed_configure_filter_mcast(struct qed_dev *cdev,
|
||||
return qed_filter_mcast_cmd(cdev, &mcast, QED_SPQ_MODE_CB, NULL);
|
||||
}
|
||||
|
||||
static int qed_configure_filter(struct qed_dev *cdev,
|
||||
struct qed_filter_params *params)
|
||||
{
|
||||
enum qed_filter_rx_mode_type accept_flags;
|
||||
|
||||
switch (params->type) {
|
||||
case QED_FILTER_TYPE_UCAST:
|
||||
return qed_configure_filter_ucast(cdev, ¶ms->filter.ucast);
|
||||
case QED_FILTER_TYPE_MCAST:
|
||||
return qed_configure_filter_mcast(cdev, ¶ms->filter.mcast);
|
||||
case QED_FILTER_TYPE_RX_MODE:
|
||||
accept_flags = params->filter.accept_flags;
|
||||
return qed_configure_filter_rx_mode(cdev, accept_flags);
|
||||
default:
|
||||
DP_NOTICE(cdev, "Unknown filter type %d\n", (int)params->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int qed_configure_arfs_searcher(struct qed_dev *cdev,
|
||||
enum qed_filter_config_mode mode)
|
||||
{
|
||||
@@ -2904,7 +2885,9 @@ static const struct qed_eth_ops qed_eth_ops_pass = {
|
||||
.q_rx_stop = &qed_stop_rxq,
|
||||
.q_tx_start = &qed_start_txq,
|
||||
.q_tx_stop = &qed_stop_txq,
|
||||
.filter_config = &qed_configure_filter,
|
||||
.filter_config_rx_mode = &qed_configure_filter_rx_mode,
|
||||
.filter_config_ucast = &qed_configure_filter_ucast,
|
||||
.filter_config_mcast = &qed_configure_filter_mcast,
|
||||
.fastpath_stop = &qed_fastpath_stop,
|
||||
.eth_cqe_completion = &qed_fp_cqe_completion,
|
||||
.get_vport_stats = &qed_get_vport_stats,
|
||||
|
||||
@@ -619,30 +619,28 @@ static int qede_set_ucast_rx_mac(struct qede_dev *edev,
|
||||
enum qed_filter_xcast_params_type opcode,
|
||||
unsigned char mac[ETH_ALEN])
|
||||
{
|
||||
struct qed_filter_params filter_cmd;
|
||||
struct qed_filter_ucast_params ucast;
|
||||
|
||||
memset(&filter_cmd, 0, sizeof(filter_cmd));
|
||||
filter_cmd.type = QED_FILTER_TYPE_UCAST;
|
||||
filter_cmd.filter.ucast.type = opcode;
|
||||
filter_cmd.filter.ucast.mac_valid = 1;
|
||||
ether_addr_copy(filter_cmd.filter.ucast.mac, mac);
|
||||
memset(&ucast, 0, sizeof(ucast));
|
||||
ucast.type = opcode;
|
||||
ucast.mac_valid = 1;
|
||||
ether_addr_copy(ucast.mac, mac);
|
||||
|
||||
return edev->ops->filter_config(edev->cdev, &filter_cmd);
|
||||
return edev->ops->filter_config_ucast(edev->cdev, &ucast);
|
||||
}
|
||||
|
||||
static int qede_set_ucast_rx_vlan(struct qede_dev *edev,
|
||||
enum qed_filter_xcast_params_type opcode,
|
||||
u16 vid)
|
||||
{
|
||||
struct qed_filter_params filter_cmd;
|
||||
struct qed_filter_ucast_params ucast;
|
||||
|
||||
memset(&filter_cmd, 0, sizeof(filter_cmd));
|
||||
filter_cmd.type = QED_FILTER_TYPE_UCAST;
|
||||
filter_cmd.filter.ucast.type = opcode;
|
||||
filter_cmd.filter.ucast.vlan_valid = 1;
|
||||
filter_cmd.filter.ucast.vlan = vid;
|
||||
memset(&ucast, 0, sizeof(ucast));
|
||||
ucast.type = opcode;
|
||||
ucast.vlan_valid = 1;
|
||||
ucast.vlan = vid;
|
||||
|
||||
return edev->ops->filter_config(edev->cdev, &filter_cmd);
|
||||
return edev->ops->filter_config_ucast(edev->cdev, &ucast);
|
||||
}
|
||||
|
||||
static int qede_config_accept_any_vlan(struct qede_dev *edev, bool action)
|
||||
@@ -1057,18 +1055,17 @@ static int qede_set_mcast_rx_mac(struct qede_dev *edev,
|
||||
enum qed_filter_xcast_params_type opcode,
|
||||
unsigned char *mac, int num_macs)
|
||||
{
|
||||
struct qed_filter_params filter_cmd;
|
||||
struct qed_filter_mcast_params mcast;
|
||||
int i;
|
||||
|
||||
memset(&filter_cmd, 0, sizeof(filter_cmd));
|
||||
filter_cmd.type = QED_FILTER_TYPE_MCAST;
|
||||
filter_cmd.filter.mcast.type = opcode;
|
||||
filter_cmd.filter.mcast.num = num_macs;
|
||||
memset(&mcast, 0, sizeof(mcast));
|
||||
mcast.type = opcode;
|
||||
mcast.num = num_macs;
|
||||
|
||||
for (i = 0; i < num_macs; i++, mac += ETH_ALEN)
|
||||
ether_addr_copy(filter_cmd.filter.mcast.mac[i], mac);
|
||||
ether_addr_copy(mcast.mac[i], mac);
|
||||
|
||||
return edev->ops->filter_config(edev->cdev, &filter_cmd);
|
||||
return edev->ops->filter_config_mcast(edev->cdev, &mcast);
|
||||
}
|
||||
|
||||
int qede_set_mac_addr(struct net_device *ndev, void *p)
|
||||
@@ -1194,7 +1191,6 @@ void qede_config_rx_mode(struct net_device *ndev)
|
||||
{
|
||||
enum qed_filter_rx_mode_type accept_flags;
|
||||
struct qede_dev *edev = netdev_priv(ndev);
|
||||
struct qed_filter_params rx_mode;
|
||||
unsigned char *uc_macs, *temp;
|
||||
struct netdev_hw_addr *ha;
|
||||
int rc, uc_count;
|
||||
@@ -1220,10 +1216,6 @@ void qede_config_rx_mode(struct net_device *ndev)
|
||||
|
||||
netif_addr_unlock_bh(ndev);
|
||||
|
||||
/* Configure the struct for the Rx mode */
|
||||
memset(&rx_mode, 0, sizeof(struct qed_filter_params));
|
||||
rx_mode.type = QED_FILTER_TYPE_RX_MODE;
|
||||
|
||||
/* Remove all previous unicast secondary macs and multicast macs
|
||||
* (configure / leave the primary mac)
|
||||
*/
|
||||
@@ -1271,8 +1263,7 @@ void qede_config_rx_mode(struct net_device *ndev)
|
||||
qede_config_accept_any_vlan(edev, false);
|
||||
}
|
||||
|
||||
rx_mode.filter.accept_flags = accept_flags;
|
||||
edev->ops->filter_config(edev->cdev, &rx_mode);
|
||||
edev->ops->filter_config_rx_mode(edev->cdev, accept_flags);
|
||||
out:
|
||||
kfree(uc_macs);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ enum mac_version {
|
||||
RTL_GIGA_MAC_VER_24,
|
||||
RTL_GIGA_MAC_VER_25,
|
||||
RTL_GIGA_MAC_VER_26,
|
||||
RTL_GIGA_MAC_VER_27,
|
||||
/* support for RTL_GIGA_MAC_VER_27 has been removed */
|
||||
RTL_GIGA_MAC_VER_28,
|
||||
RTL_GIGA_MAC_VER_29,
|
||||
RTL_GIGA_MAC_VER_30,
|
||||
|
||||
@@ -118,7 +118,6 @@ static const struct {
|
||||
[RTL_GIGA_MAC_VER_24] = {"RTL8168cp/8111cp" },
|
||||
[RTL_GIGA_MAC_VER_25] = {"RTL8168d/8111d", FIRMWARE_8168D_1},
|
||||
[RTL_GIGA_MAC_VER_26] = {"RTL8168d/8111d", FIRMWARE_8168D_2},
|
||||
[RTL_GIGA_MAC_VER_27] = {"RTL8168dp/8111dp" },
|
||||
[RTL_GIGA_MAC_VER_28] = {"RTL8168dp/8111dp" },
|
||||
[RTL_GIGA_MAC_VER_29] = {"RTL8105e", FIRMWARE_8105E_1},
|
||||
[RTL_GIGA_MAC_VER_30] = {"RTL8105e", FIRMWARE_8105E_1},
|
||||
@@ -986,33 +985,6 @@ DECLARE_RTL_COND(rtl_ocpar_cond)
|
||||
return RTL_R32(tp, OCPAR) & OCPAR_FLAG;
|
||||
}
|
||||
|
||||
static void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data)
|
||||
{
|
||||
RTL_W32(tp, OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
|
||||
RTL_W32(tp, OCPAR, OCPAR_GPHY_WRITE_CMD);
|
||||
RTL_W32(tp, EPHY_RXER_NUM, 0);
|
||||
|
||||
rtl_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100);
|
||||
}
|
||||
|
||||
static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
|
||||
{
|
||||
r8168dp_1_mdio_access(tp, reg,
|
||||
OCPDR_WRITE_CMD | (value & OCPDR_DATA_MASK));
|
||||
}
|
||||
|
||||
static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg)
|
||||
{
|
||||
r8168dp_1_mdio_access(tp, reg, OCPDR_READ_CMD);
|
||||
|
||||
mdelay(1);
|
||||
RTL_W32(tp, OCPAR, OCPAR_GPHY_READ_CMD);
|
||||
RTL_W32(tp, EPHY_RXER_NUM, 0);
|
||||
|
||||
return rtl_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
|
||||
RTL_R32(tp, OCPDR) & OCPDR_DATA_MASK : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
|
||||
|
||||
static void r8168dp_2_mdio_start(struct rtl8169_private *tp)
|
||||
@@ -1054,9 +1026,6 @@ static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
|
||||
static void rtl_writephy(struct rtl8169_private *tp, int location, int val)
|
||||
{
|
||||
switch (tp->mac_version) {
|
||||
case RTL_GIGA_MAC_VER_27:
|
||||
r8168dp_1_mdio_write(tp, location, val);
|
||||
break;
|
||||
case RTL_GIGA_MAC_VER_28:
|
||||
case RTL_GIGA_MAC_VER_31:
|
||||
r8168dp_2_mdio_write(tp, location, val);
|
||||
@@ -1073,8 +1042,6 @@ static void rtl_writephy(struct rtl8169_private *tp, int location, int val)
|
||||
static int rtl_readphy(struct rtl8169_private *tp, int location)
|
||||
{
|
||||
switch (tp->mac_version) {
|
||||
case RTL_GIGA_MAC_VER_27:
|
||||
return r8168dp_1_mdio_read(tp, location);
|
||||
case RTL_GIGA_MAC_VER_28:
|
||||
case RTL_GIGA_MAC_VER_31:
|
||||
return r8168dp_2_mdio_read(tp, location);
|
||||
@@ -1236,7 +1203,6 @@ static bool r8168ep_check_dash(struct rtl8169_private *tp)
|
||||
static enum rtl_dash_type rtl_check_dash(struct rtl8169_private *tp)
|
||||
{
|
||||
switch (tp->mac_version) {
|
||||
case RTL_GIGA_MAC_VER_27:
|
||||
case RTL_GIGA_MAC_VER_28:
|
||||
case RTL_GIGA_MAC_VER_31:
|
||||
return r8168dp_check_dash(tp) ? RTL_DASH_DP : RTL_DASH_NONE;
|
||||
@@ -2041,8 +2007,7 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii)
|
||||
|
||||
/* 8168DP family. */
|
||||
/* It seems this early RTL8168dp version never made it to
|
||||
* the wild. Let's see whether somebody complains, if not
|
||||
* we'll remove support for this chip version completely.
|
||||
* the wild. Support has been removed.
|
||||
* { 0x7cf, 0x288, RTL_GIGA_MAC_VER_27 },
|
||||
*/
|
||||
{ 0x7cf, 0x28a, RTL_GIGA_MAC_VER_28 },
|
||||
@@ -2372,7 +2337,7 @@ static void rtl_jumbo_config(struct rtl8169_private *tp)
|
||||
r8168c_hw_jumbo_disable(tp);
|
||||
}
|
||||
break;
|
||||
case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28:
|
||||
case RTL_GIGA_MAC_VER_28:
|
||||
if (jumbo)
|
||||
r8168dp_hw_jumbo_enable(tp);
|
||||
else
|
||||
@@ -3720,7 +3685,6 @@ static void rtl_hw_config(struct rtl8169_private *tp)
|
||||
[RTL_GIGA_MAC_VER_24] = rtl_hw_start_8168cp_3,
|
||||
[RTL_GIGA_MAC_VER_25] = rtl_hw_start_8168d,
|
||||
[RTL_GIGA_MAC_VER_26] = rtl_hw_start_8168d,
|
||||
[RTL_GIGA_MAC_VER_27] = rtl_hw_start_8168d,
|
||||
[RTL_GIGA_MAC_VER_28] = rtl_hw_start_8168d_4,
|
||||
[RTL_GIGA_MAC_VER_29] = rtl_hw_start_8105e_1,
|
||||
[RTL_GIGA_MAC_VER_30] = rtl_hw_start_8105e_2,
|
||||
@@ -3983,7 +3947,6 @@ static void rtl8169_cleanup(struct rtl8169_private *tp, bool going_down)
|
||||
goto no_reset;
|
||||
|
||||
switch (tp->mac_version) {
|
||||
case RTL_GIGA_MAC_VER_27:
|
||||
case RTL_GIGA_MAC_VER_28:
|
||||
case RTL_GIGA_MAC_VER_31:
|
||||
rtl_loop_wait_low(tp, &rtl_npq_cond, 20, 2000);
|
||||
|
||||
@@ -548,64 +548,6 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp,
|
||||
rtl8168d_apply_firmware_cond(tp, phydev, 0xb300);
|
||||
}
|
||||
|
||||
static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp,
|
||||
struct phy_device *phydev)
|
||||
{
|
||||
static const struct phy_reg phy_reg_init[] = {
|
||||
{ 0x1f, 0x0002 },
|
||||
{ 0x10, 0x0008 },
|
||||
{ 0x0d, 0x006c },
|
||||
|
||||
{ 0x1f, 0x0000 },
|
||||
{ 0x0d, 0xf880 },
|
||||
|
||||
{ 0x1f, 0x0001 },
|
||||
{ 0x17, 0x0cc0 },
|
||||
|
||||
{ 0x1f, 0x0001 },
|
||||
{ 0x0b, 0xa4d8 },
|
||||
{ 0x09, 0x281c },
|
||||
{ 0x07, 0x2883 },
|
||||
{ 0x0a, 0x6b35 },
|
||||
{ 0x1d, 0x3da4 },
|
||||
{ 0x1c, 0xeffd },
|
||||
{ 0x14, 0x7f52 },
|
||||
{ 0x18, 0x7fc6 },
|
||||
{ 0x08, 0x0601 },
|
||||
{ 0x06, 0x4063 },
|
||||
{ 0x10, 0xf074 },
|
||||
{ 0x1f, 0x0003 },
|
||||
{ 0x13, 0x0789 },
|
||||
{ 0x12, 0xf4bd },
|
||||
{ 0x1a, 0x04fd },
|
||||
{ 0x14, 0x84b0 },
|
||||
{ 0x1f, 0x0000 },
|
||||
{ 0x00, 0x9200 },
|
||||
|
||||
{ 0x1f, 0x0005 },
|
||||
{ 0x01, 0x0340 },
|
||||
{ 0x1f, 0x0001 },
|
||||
{ 0x04, 0x4000 },
|
||||
{ 0x03, 0x1d21 },
|
||||
{ 0x02, 0x0c32 },
|
||||
{ 0x01, 0x0200 },
|
||||
{ 0x00, 0x5554 },
|
||||
{ 0x04, 0x4800 },
|
||||
{ 0x04, 0x4000 },
|
||||
{ 0x04, 0xf000 },
|
||||
{ 0x03, 0xdf01 },
|
||||
{ 0x02, 0xdf20 },
|
||||
{ 0x01, 0x101a },
|
||||
{ 0x00, 0xa0ff },
|
||||
{ 0x04, 0xf800 },
|
||||
{ 0x04, 0xf000 },
|
||||
{ 0x1f, 0x0000 },
|
||||
};
|
||||
|
||||
rtl_writephy_batch(phydev, phy_reg_init);
|
||||
r8168d_modify_extpage(phydev, 0x0023, 0x16, 0xffff, 0x0000);
|
||||
}
|
||||
|
||||
static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp,
|
||||
struct phy_device *phydev)
|
||||
{
|
||||
@@ -1332,7 +1274,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
|
||||
[RTL_GIGA_MAC_VER_24] = rtl8168cp_2_hw_phy_config,
|
||||
[RTL_GIGA_MAC_VER_25] = rtl8168d_1_hw_phy_config,
|
||||
[RTL_GIGA_MAC_VER_26] = rtl8168d_2_hw_phy_config,
|
||||
[RTL_GIGA_MAC_VER_27] = rtl8168d_3_hw_phy_config,
|
||||
[RTL_GIGA_MAC_VER_28] = rtl8168d_4_hw_phy_config,
|
||||
[RTL_GIGA_MAC_VER_29] = rtl8105e_hw_phy_config,
|
||||
[RTL_GIGA_MAC_VER_30] = rtl8105e_hw_phy_config,
|
||||
|
||||
@@ -81,6 +81,30 @@ static int nsim_set_ringparam(struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nsim_get_channels(struct net_device *dev, struct ethtool_channels *ch)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
ch->max_combined = ns->nsim_bus_dev->num_queues;
|
||||
ch->combined_count = ns->ethtool.channels;
|
||||
}
|
||||
|
||||
static int
|
||||
nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
err = netif_set_real_num_queues(dev, ch->combined_count,
|
||||
ch->combined_count);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ns->ethtool.channels = ch->combined_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nsim_get_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
|
||||
{
|
||||
@@ -118,6 +142,8 @@ static const struct ethtool_ops nsim_ethtool_ops = {
|
||||
.get_coalesce = nsim_get_coalesce,
|
||||
.get_ringparam = nsim_get_ringparam,
|
||||
.set_ringparam = nsim_set_ringparam,
|
||||
.get_channels = nsim_get_channels,
|
||||
.set_channels = nsim_set_channels,
|
||||
.get_fecparam = nsim_get_fecparam,
|
||||
.set_fecparam = nsim_set_fecparam,
|
||||
};
|
||||
@@ -141,6 +167,8 @@ void nsim_ethtool_init(struct netdevsim *ns)
|
||||
ns->ethtool.fec.fec = ETHTOOL_FEC_NONE;
|
||||
ns->ethtool.fec.active_fec = ETHTOOL_FEC_NONE;
|
||||
|
||||
ns->ethtool.channels = ns->nsim_bus_dev->num_queues;
|
||||
|
||||
ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir);
|
||||
|
||||
debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err);
|
||||
|
||||
@@ -62,6 +62,7 @@ struct nsim_ethtool_pauseparam {
|
||||
struct nsim_ethtool {
|
||||
u32 get_err;
|
||||
u32 set_err;
|
||||
u32 channels;
|
||||
struct nsim_ethtool_pauseparam pauseparam;
|
||||
struct ethtool_coalesce coalesce;
|
||||
struct ethtool_ringparam ring;
|
||||
|
||||
@@ -1420,6 +1420,19 @@ static struct phy_driver at803x_driver[] = {
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
}, {
|
||||
/* QCA8327 */
|
||||
.phy_id = QCA8327_PHY_ID,
|
||||
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
.name = "QCA PHY 8327",
|
||||
/* PHY_GBIT_FEATURES */
|
||||
.probe = at803x_probe,
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
.config_init = qca83xx_config_init,
|
||||
.soft_reset = genphy_soft_reset,
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
}, };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
@@ -1430,6 +1443,8 @@ static struct mdio_device_id __maybe_unused atheros_tbl[] = {
|
||||
{ PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
|
||||
{ PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
|
||||
{ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
|
||||
{ PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
|
||||
{ PHY_ID_MATCH_EXACT(QCA8327_PHY_ID) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ config RPMSG_WWAN_CTRL
|
||||
config IOSM
|
||||
tristate "IOSM Driver for Intel M.2 WWAN Device"
|
||||
depends on INTEL_IOMMU
|
||||
select NET_DEVLINK
|
||||
help
|
||||
This driver enables Intel M.2 WWAN Device communication.
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ iosm-y = \
|
||||
iosm_ipc_protocol.o \
|
||||
iosm_ipc_protocol_ops.o \
|
||||
iosm_ipc_mux.o \
|
||||
iosm_ipc_mux_codec.o
|
||||
iosm_ipc_mux_codec.o \
|
||||
iosm_ipc_devlink.o \
|
||||
iosm_ipc_flash.o \
|
||||
iosm_ipc_coredump.o
|
||||
|
||||
obj-$(CONFIG_IOSM) := iosm.o
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "iosm_ipc_chnl_cfg.h"
|
||||
|
||||
/* Max. sizes of a downlink buffers */
|
||||
#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (16 * 1024)
|
||||
#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (64 * 1024)
|
||||
#define IPC_MEM_MAX_DL_LOOPBACK_SIZE (1 * 1024 * 1024)
|
||||
#define IPC_MEM_MAX_DL_AT_BUF_SIZE 2048
|
||||
#define IPC_MEM_MAX_DL_RPC_BUF_SIZE (32 * 1024)
|
||||
@@ -60,6 +60,10 @@ static struct ipc_chnl_cfg modem_cfg[] = {
|
||||
{ IPC_MEM_CTRL_CHL_ID_6, IPC_MEM_PIPE_12, IPC_MEM_PIPE_13,
|
||||
IPC_MEM_MAX_TDS_MBIM, IPC_MEM_MAX_TDS_MBIM,
|
||||
IPC_MEM_MAX_DL_MBIM_BUF_SIZE, WWAN_PORT_MBIM },
|
||||
/* Flash Channel/Coredump Channel */
|
||||
{ IPC_MEM_CTRL_CHL_ID_7, IPC_MEM_PIPE_0, IPC_MEM_PIPE_1,
|
||||
IPC_MEM_MAX_TDS_FLASH_UL, IPC_MEM_MAX_TDS_FLASH_DL,
|
||||
IPC_MEM_MAX_DL_FLASH_BUF_SIZE, WWAN_PORT_UNKNOWN },
|
||||
};
|
||||
|
||||
int ipc_chnl_cfg_get(struct ipc_chnl_cfg *chnl_cfg, int index)
|
||||
|
||||
@@ -23,6 +23,7 @@ enum ipc_channel_id {
|
||||
IPC_MEM_CTRL_CHL_ID_4,
|
||||
IPC_MEM_CTRL_CHL_ID_5,
|
||||
IPC_MEM_CTRL_CHL_ID_6,
|
||||
IPC_MEM_CTRL_CHL_ID_7,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
110
drivers/net/wwan/iosm/iosm_ipc_coredump.c
Normal file
110
drivers/net/wwan/iosm/iosm_ipc_coredump.c
Normal file
@@ -0,0 +1,110 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include "iosm_ipc_coredump.h"
|
||||
|
||||
/* Collect coredump data from modem */
|
||||
int ipc_coredump_collect(struct iosm_devlink *devlink, u8 **data, int entry,
|
||||
u32 region_size)
|
||||
{
|
||||
int ret, bytes_to_read, bytes_read = 0, i = 0;
|
||||
s32 remaining;
|
||||
u8 *data_ptr;
|
||||
|
||||
data_ptr = vmalloc(region_size);
|
||||
if (!data_ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
remaining = devlink->cd_file_info[entry].actual_size;
|
||||
ret = ipc_devlink_send_cmd(devlink, rpsi_cmd_coredump_get, entry);
|
||||
if (ret) {
|
||||
dev_err(devlink->dev, "Send coredump_get cmd failed");
|
||||
goto get_cd_fail;
|
||||
}
|
||||
while (remaining > 0) {
|
||||
bytes_to_read = min(remaining, MAX_DATA_SIZE);
|
||||
bytes_read = 0;
|
||||
ret = ipc_imem_sys_devlink_read(devlink, data_ptr + i,
|
||||
bytes_to_read, &bytes_read);
|
||||
if (ret) {
|
||||
dev_err(devlink->dev, "CD data read failed");
|
||||
goto get_cd_fail;
|
||||
}
|
||||
remaining -= bytes_read;
|
||||
i += bytes_read;
|
||||
}
|
||||
|
||||
*data = data_ptr;
|
||||
|
||||
return ret;
|
||||
get_cd_fail:
|
||||
vfree(data_ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get coredump list to be collected from modem */
|
||||
int ipc_coredump_get_list(struct iosm_devlink *devlink, u16 cmd)
|
||||
{
|
||||
u32 byte_read, num_entries, file_size;
|
||||
struct iosm_cd_table *cd_table;
|
||||
u8 size[MAX_SIZE_LEN], i;
|
||||
char *filename;
|
||||
int ret = 0;
|
||||
|
||||
cd_table = kzalloc(MAX_CD_LIST_SIZE, GFP_KERNEL);
|
||||
if (!cd_table) {
|
||||
ret = -ENOMEM;
|
||||
goto cd_init_fail;
|
||||
}
|
||||
|
||||
ret = ipc_devlink_send_cmd(devlink, cmd, MAX_CD_LIST_SIZE);
|
||||
if (ret) {
|
||||
dev_err(devlink->dev, "rpsi_cmd_coredump_start failed");
|
||||
goto cd_init_fail;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(devlink, (u8 *)cd_table,
|
||||
MAX_CD_LIST_SIZE, &byte_read);
|
||||
if (ret) {
|
||||
dev_err(devlink->dev, "Coredump data is invalid");
|
||||
goto cd_init_fail;
|
||||
}
|
||||
|
||||
if (byte_read != MAX_CD_LIST_SIZE)
|
||||
goto cd_init_fail;
|
||||
|
||||
if (cmd == rpsi_cmd_coredump_start) {
|
||||
num_entries = le32_to_cpu(cd_table->list.num_entries);
|
||||
if (num_entries == 0 || num_entries > IOSM_NOF_CD_REGION) {
|
||||
ret = -EINVAL;
|
||||
goto cd_init_fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
file_size = le32_to_cpu(cd_table->list.entry[i].size);
|
||||
filename = cd_table->list.entry[i].filename;
|
||||
|
||||
if (file_size > devlink->cd_file_info[i].default_size) {
|
||||
ret = -EINVAL;
|
||||
goto cd_init_fail;
|
||||
}
|
||||
|
||||
devlink->cd_file_info[i].actual_size = file_size;
|
||||
dev_dbg(devlink->dev, "file: %s actual size %d",
|
||||
filename, file_size);
|
||||
devlink_flash_update_status_notify(devlink->devlink_ctx,
|
||||
filename,
|
||||
"FILENAME", 0, 0);
|
||||
snprintf(size, sizeof(size), "%d", file_size);
|
||||
devlink_flash_update_status_notify(devlink->devlink_ctx,
|
||||
size, "FILE SIZE",
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
cd_init_fail:
|
||||
kfree(cd_table);
|
||||
return ret;
|
||||
}
|
||||
75
drivers/net/wwan/iosm/iosm_ipc_coredump.h
Normal file
75
drivers/net/wwan/iosm/iosm_ipc_coredump.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2020-2021 Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef _IOSM_IPC_COREDUMP_H_
|
||||
#define _IOSM_IPC_COREDUMP_H_
|
||||
|
||||
#include "iosm_ipc_devlink.h"
|
||||
|
||||
/* Max number of bytes to receive for Coredump list structure */
|
||||
#define MAX_CD_LIST_SIZE 0x1000
|
||||
|
||||
/* Max buffer allocated to receive coredump data */
|
||||
#define MAX_DATA_SIZE 0x00010000
|
||||
|
||||
/* Max number of file entries */
|
||||
#define MAX_NOF_ENTRY 256
|
||||
|
||||
/* Max length */
|
||||
#define MAX_SIZE_LEN 32
|
||||
|
||||
/**
|
||||
* struct iosm_cd_list_entry - Structure to hold coredump file info.
|
||||
* @size: Number of bytes for the entry
|
||||
* @filename: Coredump filename to be generated on host
|
||||
*/
|
||||
struct iosm_cd_list_entry {
|
||||
__le32 size;
|
||||
char filename[IOSM_MAX_FILENAME_LEN];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iosm_cd_list - Structure to hold list of coredump files
|
||||
* to be collected.
|
||||
* @num_entries: Number of entries to be received
|
||||
* @entry: Contains File info
|
||||
*/
|
||||
struct iosm_cd_list {
|
||||
__le32 num_entries;
|
||||
struct iosm_cd_list_entry entry[MAX_NOF_ENTRY];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iosm_cd_table - Common Coredump table
|
||||
* @version: Version of coredump structure
|
||||
* @list: Coredump list structure
|
||||
*/
|
||||
struct iosm_cd_table {
|
||||
__le32 version;
|
||||
struct iosm_cd_list list;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* ipc_coredump_collect - To collect coredump
|
||||
* @devlink: Pointer to devlink instance.
|
||||
* @data: Pointer to snapshot
|
||||
* @entry: ID of requested snapshot
|
||||
* @region_size: Region size
|
||||
*
|
||||
* Returns: 0 on success, error on failure
|
||||
*/
|
||||
int ipc_coredump_collect(struct iosm_devlink *devlink, u8 **data, int entry,
|
||||
u32 region_size);
|
||||
|
||||
/**
|
||||
* ipc_coredump_get_list - Get coredump list
|
||||
* @devlink: Pointer to devlink instance.
|
||||
* @cmd: RPSI command to be sent
|
||||
*
|
||||
* Returns: 0 on success, error on failure
|
||||
*/
|
||||
int ipc_coredump_get_list(struct iosm_devlink *devlink, u16 cmd);
|
||||
|
||||
#endif /* _IOSM_IPC_COREDUMP_H_ */
|
||||
360
drivers/net/wwan/iosm/iosm_ipc_devlink.c
Normal file
360
drivers/net/wwan/iosm/iosm_ipc_devlink.c
Normal file
@@ -0,0 +1,360 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include "iosm_ipc_chnl_cfg.h"
|
||||
#include "iosm_ipc_coredump.h"
|
||||
#include "iosm_ipc_devlink.h"
|
||||
#include "iosm_ipc_flash.h"
|
||||
|
||||
/* Coredump list */
|
||||
static struct iosm_coredump_file_info list[IOSM_NOF_CD_REGION] = {
|
||||
{"report.json", REPORT_JSON_SIZE,},
|
||||
{"coredump.fcd", COREDUMP_FCD_SIZE,},
|
||||
{"cdd.log", CDD_LOG_SIZE,},
|
||||
{"eeprom.bin", EEPROM_BIN_SIZE,},
|
||||
{"bootcore_trace.bin", BOOTCORE_TRC_BIN_SIZE,},
|
||||
{"bootcore_prev_trace.bin", BOOTCORE_PREV_TRC_BIN_SIZE,},
|
||||
};
|
||||
|
||||
/* Get the param values for the specific param ID's */
|
||||
static int ipc_devlink_get_param(struct devlink *dl, u32 id,
|
||||
struct devlink_param_gset_ctx *ctx)
|
||||
{
|
||||
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
|
||||
int rc = 0;
|
||||
|
||||
switch (id) {
|
||||
case IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH:
|
||||
ctx->val.vu8 = ipc_devlink->param.erase_full_flash;
|
||||
break;
|
||||
|
||||
case IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION:
|
||||
ctx->val.vu8 = ipc_devlink->param.download_region;
|
||||
break;
|
||||
|
||||
case IOSM_DEVLINK_PARAM_ID_ADDRESS:
|
||||
ctx->val.vu32 = ipc_devlink->param.address;
|
||||
break;
|
||||
|
||||
case IOSM_DEVLINK_PARAM_ID_REGION_COUNT:
|
||||
ctx->val.vu8 = ipc_devlink->param.region_count;
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Set the param values for the specific param ID's */
|
||||
static int ipc_devlink_set_param(struct devlink *dl, u32 id,
|
||||
struct devlink_param_gset_ctx *ctx)
|
||||
{
|
||||
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
|
||||
int rc = 0;
|
||||
|
||||
switch (id) {
|
||||
case IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH:
|
||||
ipc_devlink->param.erase_full_flash = ctx->val.vu8;
|
||||
break;
|
||||
|
||||
case IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION:
|
||||
ipc_devlink->param.download_region = ctx->val.vu8;
|
||||
break;
|
||||
|
||||
case IOSM_DEVLINK_PARAM_ID_ADDRESS:
|
||||
ipc_devlink->param.address = ctx->val.vu32;
|
||||
break;
|
||||
|
||||
case IOSM_DEVLINK_PARAM_ID_REGION_COUNT:
|
||||
ipc_devlink->param.region_count = ctx->val.vu8;
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Devlink param structure array */
|
||||
static const struct devlink_param iosm_devlink_params[] = {
|
||||
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH,
|
||||
"erase_full_flash", DEVLINK_PARAM_TYPE_BOOL,
|
||||
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
|
||||
ipc_devlink_get_param, ipc_devlink_set_param,
|
||||
NULL),
|
||||
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION,
|
||||
"download_region", DEVLINK_PARAM_TYPE_BOOL,
|
||||
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
|
||||
ipc_devlink_get_param, ipc_devlink_set_param,
|
||||
NULL),
|
||||
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_ADDRESS,
|
||||
"address", DEVLINK_PARAM_TYPE_U32,
|
||||
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
|
||||
ipc_devlink_get_param, ipc_devlink_set_param,
|
||||
NULL),
|
||||
DEVLINK_PARAM_DRIVER(IOSM_DEVLINK_PARAM_ID_REGION_COUNT,
|
||||
"region_count", DEVLINK_PARAM_TYPE_U8,
|
||||
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
|
||||
ipc_devlink_get_param, ipc_devlink_set_param,
|
||||
NULL),
|
||||
};
|
||||
|
||||
/* Get devlink flash component type */
|
||||
static enum iosm_flash_comp_type
|
||||
ipc_devlink_get_flash_comp_type(const char comp_str[], u32 len)
|
||||
{
|
||||
enum iosm_flash_comp_type fls_type;
|
||||
|
||||
if (!strncmp("PSI", comp_str, len))
|
||||
fls_type = FLASH_COMP_TYPE_PSI;
|
||||
else if (!strncmp("EBL", comp_str, len))
|
||||
fls_type = FLASH_COMP_TYPE_EBL;
|
||||
else if (!strncmp("FLS", comp_str, len))
|
||||
fls_type = FLASH_COMP_TYPE_FLS;
|
||||
else
|
||||
fls_type = FLASH_COMP_TYPE_INVAL;
|
||||
|
||||
return fls_type;
|
||||
}
|
||||
|
||||
/* Function triggered on devlink flash command
|
||||
* Flash update function which calls multiple functions based on
|
||||
* component type specified in the flash command
|
||||
*/
|
||||
static int ipc_devlink_flash_update(struct devlink *devlink,
|
||||
struct devlink_flash_update_params *params,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct iosm_devlink *ipc_devlink = devlink_priv(devlink);
|
||||
enum iosm_flash_comp_type fls_type;
|
||||
u32 rc = -EINVAL;
|
||||
u8 *mdm_rsp;
|
||||
|
||||
mdm_rsp = kzalloc(IOSM_EBL_DW_PACK_SIZE, GFP_KERNEL);
|
||||
if (!mdm_rsp)
|
||||
return -ENOMEM;
|
||||
|
||||
fls_type = ipc_devlink_get_flash_comp_type(params->component,
|
||||
strlen(params->component));
|
||||
|
||||
switch (fls_type) {
|
||||
case FLASH_COMP_TYPE_PSI:
|
||||
rc = ipc_flash_boot_psi(ipc_devlink, params->fw);
|
||||
break;
|
||||
case FLASH_COMP_TYPE_EBL:
|
||||
rc = ipc_flash_boot_ebl(ipc_devlink, params->fw);
|
||||
if (!rc)
|
||||
rc = ipc_flash_boot_set_capabilities(ipc_devlink,
|
||||
mdm_rsp);
|
||||
if (!rc)
|
||||
rc = ipc_flash_read_swid(ipc_devlink, mdm_rsp);
|
||||
break;
|
||||
case FLASH_COMP_TYPE_FLS:
|
||||
rc = ipc_flash_send_fls(ipc_devlink, params->fw, mdm_rsp);
|
||||
break;
|
||||
default:
|
||||
devlink_flash_update_status_notify(devlink, "Invalid component",
|
||||
params->component, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
devlink_flash_update_status_notify(devlink, "Flashing success",
|
||||
params->component, 0, 0);
|
||||
else
|
||||
devlink_flash_update_status_notify(devlink, "Flashing failed",
|
||||
params->component, 0, 0);
|
||||
|
||||
kfree(mdm_rsp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Call back function for devlink ops */
|
||||
static const struct devlink_ops devlink_flash_ops = {
|
||||
.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT,
|
||||
.flash_update = ipc_devlink_flash_update,
|
||||
};
|
||||
|
||||
/* Send command to modem to collect data */
|
||||
int ipc_devlink_send_cmd(struct iosm_devlink *ipc_devlink, u16 cmd, u32 entry)
|
||||
{
|
||||
struct iosm_rpsi_cmd rpsi_cmd;
|
||||
|
||||
rpsi_cmd.param.dword = cpu_to_le32(entry);
|
||||
rpsi_cmd.cmd = cpu_to_le16(cmd);
|
||||
rpsi_cmd.crc = rpsi_cmd.param.word[0] ^ rpsi_cmd.param.word[1] ^
|
||||
rpsi_cmd.cmd;
|
||||
|
||||
return ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&rpsi_cmd,
|
||||
sizeof(rpsi_cmd));
|
||||
}
|
||||
|
||||
static int ipc_devlink_coredump_snapshot(struct devlink *dl,
|
||||
const struct devlink_region_ops *ops,
|
||||
struct netlink_ext_ack *extack,
|
||||
u8 **data)
|
||||
{
|
||||
struct iosm_devlink *ipc_devlink = devlink_priv(dl);
|
||||
struct iosm_coredump_file_info *cd_list = ops->priv;
|
||||
u32 region_size;
|
||||
int rc;
|
||||
|
||||
dev_dbg(ipc_devlink->dev, "Region:%s, ID:%d", ops->name,
|
||||
cd_list->entry);
|
||||
region_size = cd_list->default_size;
|
||||
rc = ipc_coredump_collect(ipc_devlink, data, cd_list->entry,
|
||||
region_size);
|
||||
if (rc) {
|
||||
dev_err(ipc_devlink->dev, "Fail to create snapshot,err %d", rc);
|
||||
goto coredump_collect_err;
|
||||
}
|
||||
|
||||
/* Send coredump end cmd indicating end of coredump collection */
|
||||
if (cd_list->entry == (IOSM_NOF_CD_REGION - 1))
|
||||
ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
|
||||
|
||||
return rc;
|
||||
coredump_collect_err:
|
||||
ipc_coredump_get_list(ipc_devlink, rpsi_cmd_coredump_end);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* To create regions for coredump files */
|
||||
static int ipc_devlink_create_region(struct iosm_devlink *devlink)
|
||||
{
|
||||
struct devlink_region_ops *mdm_coredump;
|
||||
int rc = 0;
|
||||
u8 i;
|
||||
|
||||
mdm_coredump = devlink->iosm_devlink_mdm_coredump;
|
||||
for (i = 0; i < IOSM_NOF_CD_REGION; i++) {
|
||||
mdm_coredump[i].name = list[i].filename;
|
||||
mdm_coredump[i].snapshot = ipc_devlink_coredump_snapshot;
|
||||
mdm_coredump[i].destructor = vfree;
|
||||
devlink->cd_regions[i] =
|
||||
devlink_region_create(devlink->devlink_ctx,
|
||||
&mdm_coredump[i], MAX_SNAPSHOTS,
|
||||
list[i].default_size);
|
||||
|
||||
if (IS_ERR(devlink->cd_regions[i])) {
|
||||
rc = PTR_ERR(devlink->cd_regions[i]);
|
||||
dev_err(devlink->dev, "Devlink region fail,err %d", rc);
|
||||
/* Delete previously created regions */
|
||||
for ( ; i > 0; i--)
|
||||
devlink_region_destroy(devlink->cd_regions[i]);
|
||||
goto region_create_fail;
|
||||
}
|
||||
list[i].entry = i;
|
||||
mdm_coredump[i].priv = list + i;
|
||||
}
|
||||
region_create_fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* To Destroy devlink regions */
|
||||
static void ipc_devlink_destroy_region(struct iosm_devlink *ipc_devlink)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < IOSM_NOF_CD_REGION; i++)
|
||||
devlink_region_destroy(ipc_devlink->cd_regions[i]);
|
||||
}
|
||||
|
||||
/* Handle registration to devlink framework */
|
||||
struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem)
|
||||
{
|
||||
struct ipc_chnl_cfg chnl_cfg_flash = { 0 };
|
||||
struct iosm_devlink *ipc_devlink;
|
||||
struct devlink *devlink_ctx;
|
||||
int rc;
|
||||
|
||||
devlink_ctx = devlink_alloc(&devlink_flash_ops,
|
||||
sizeof(struct iosm_devlink),
|
||||
ipc_imem->dev);
|
||||
if (!devlink_ctx) {
|
||||
dev_err(ipc_imem->dev, "devlink_alloc failed");
|
||||
goto devlink_alloc_fail;
|
||||
}
|
||||
|
||||
ipc_devlink = devlink_priv(devlink_ctx);
|
||||
ipc_devlink->devlink_ctx = devlink_ctx;
|
||||
ipc_devlink->pcie = ipc_imem->pcie;
|
||||
ipc_devlink->dev = ipc_imem->dev;
|
||||
rc = devlink_register(devlink_ctx);
|
||||
if (rc) {
|
||||
dev_err(ipc_devlink->dev, "devlink_register failed rc %d", rc);
|
||||
goto free_dl;
|
||||
}
|
||||
|
||||
rc = devlink_params_register(devlink_ctx, iosm_devlink_params,
|
||||
ARRAY_SIZE(iosm_devlink_params));
|
||||
if (rc) {
|
||||
dev_err(ipc_devlink->dev,
|
||||
"devlink_params_register failed. rc %d", rc);
|
||||
goto param_reg_fail;
|
||||
}
|
||||
|
||||
devlink_params_publish(devlink_ctx);
|
||||
ipc_devlink->cd_file_info = list;
|
||||
|
||||
rc = ipc_devlink_create_region(ipc_devlink);
|
||||
if (rc) {
|
||||
dev_err(ipc_devlink->dev, "Devlink Region create failed, rc %d",
|
||||
rc);
|
||||
goto region_create_fail;
|
||||
}
|
||||
|
||||
if (ipc_chnl_cfg_get(&chnl_cfg_flash, IPC_MEM_CTRL_CHL_ID_7) < 0)
|
||||
goto chnl_get_fail;
|
||||
|
||||
ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL,
|
||||
chnl_cfg_flash, IRQ_MOD_OFF);
|
||||
|
||||
init_completion(&ipc_devlink->devlink_sio.read_sem);
|
||||
skb_queue_head_init(&ipc_devlink->devlink_sio.rx_list);
|
||||
|
||||
dev_dbg(ipc_devlink->dev, "iosm devlink register success");
|
||||
|
||||
return ipc_devlink;
|
||||
|
||||
chnl_get_fail:
|
||||
ipc_devlink_destroy_region(ipc_devlink);
|
||||
region_create_fail:
|
||||
devlink_params_unpublish(devlink_ctx);
|
||||
devlink_params_unregister(devlink_ctx, iosm_devlink_params,
|
||||
ARRAY_SIZE(iosm_devlink_params));
|
||||
param_reg_fail:
|
||||
devlink_unregister(devlink_ctx);
|
||||
free_dl:
|
||||
devlink_free(devlink_ctx);
|
||||
devlink_alloc_fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Handle unregistration of devlink */
|
||||
void ipc_devlink_deinit(struct iosm_devlink *ipc_devlink)
|
||||
{
|
||||
struct devlink *devlink_ctx = ipc_devlink->devlink_ctx;
|
||||
|
||||
ipc_devlink_destroy_region(ipc_devlink);
|
||||
devlink_params_unpublish(devlink_ctx);
|
||||
devlink_params_unregister(devlink_ctx, iosm_devlink_params,
|
||||
ARRAY_SIZE(iosm_devlink_params));
|
||||
if (ipc_devlink->devlink_sio.devlink_read_pend) {
|
||||
complete(&ipc_devlink->devlink_sio.read_sem);
|
||||
complete(&ipc_devlink->devlink_sio.channel->ul_sem);
|
||||
}
|
||||
if (!ipc_devlink->devlink_sio.devlink_read_pend)
|
||||
skb_queue_purge(&ipc_devlink->devlink_sio.rx_list);
|
||||
|
||||
ipc_imem_sys_devlink_close(ipc_devlink);
|
||||
devlink_unregister(devlink_ctx);
|
||||
devlink_free(devlink_ctx);
|
||||
}
|
||||
207
drivers/net/wwan/iosm/iosm_ipc_devlink.h
Normal file
207
drivers/net/wwan/iosm/iosm_ipc_devlink.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2020-2021 Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef _IOSM_IPC_DEVLINK_H_
|
||||
#define _IOSM_IPC_DEVLINK_H_
|
||||
|
||||
#include <net/devlink.h>
|
||||
|
||||
#include "iosm_ipc_imem.h"
|
||||
#include "iosm_ipc_imem_ops.h"
|
||||
#include "iosm_ipc_pcie.h"
|
||||
|
||||
/* MAX file name length */
|
||||
#define IOSM_MAX_FILENAME_LEN 32
|
||||
/* EBL response size */
|
||||
#define IOSM_EBL_RSP_SIZE 76
|
||||
/* MAX number of regions supported */
|
||||
#define IOSM_NOF_CD_REGION 6
|
||||
/* MAX number of SNAPSHOTS supported */
|
||||
#define MAX_SNAPSHOTS 1
|
||||
/* Default Coredump file size */
|
||||
#define REPORT_JSON_SIZE 0x800
|
||||
#define COREDUMP_FCD_SIZE 0x10E00000
|
||||
#define CDD_LOG_SIZE 0x30000
|
||||
#define EEPROM_BIN_SIZE 0x10000
|
||||
#define BOOTCORE_TRC_BIN_SIZE 0x8000
|
||||
#define BOOTCORE_PREV_TRC_BIN_SIZE 0x20000
|
||||
|
||||
/**
|
||||
* enum iosm_devlink_param_id - Enum type to different devlink params
|
||||
* @IOSM_DEVLINK_PARAM_ID_BASE: Devlink param base ID
|
||||
* @IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH: Set if full erase required
|
||||
* @IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION: Set if fls file to be
|
||||
* flashed is Loadmap/region file
|
||||
* @IOSM_DEVLINK_PARAM_ID_ADDRESS: Address of the region to be
|
||||
* flashed
|
||||
* @IOSM_DEVLINK_PARAM_ID_REGION_COUNT: Max region count
|
||||
*/
|
||||
|
||||
enum iosm_devlink_param_id {
|
||||
IOSM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
|
||||
IOSM_DEVLINK_PARAM_ID_ERASE_FULL_FLASH,
|
||||
IOSM_DEVLINK_PARAM_ID_DOWNLOAD_REGION,
|
||||
IOSM_DEVLINK_PARAM_ID_ADDRESS,
|
||||
IOSM_DEVLINK_PARAM_ID_REGION_COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_rpsi_cmd_code - Enum type for RPSI command list
|
||||
* @rpsi_cmd_code_ebl: Command to load ebl
|
||||
* @rpsi_cmd_coredump_start: Command to get list of files and
|
||||
* file size info from PSI
|
||||
* @rpsi_cmd_coredump_get: Command to get the coredump data
|
||||
* @rpsi_cmd_coredump_end: Command to stop receiving the coredump
|
||||
*/
|
||||
enum iosm_rpsi_cmd_code {
|
||||
rpsi_cmd_code_ebl = 0x02,
|
||||
rpsi_cmd_coredump_start = 0x10,
|
||||
rpsi_cmd_coredump_get = 0x11,
|
||||
rpsi_cmd_coredump_end = 0x12,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_flash_comp_type - Enum for different flash component types
|
||||
* @FLASH_COMP_TYPE_PSI: PSI flash comp type
|
||||
* @FLASH_COMP_TYPE_EBL: EBL flash comp type
|
||||
* @FLASH_COMP_TYPE_FLS: FLS flash comp type
|
||||
* @FLASH_COMP_TYPE_INVAL: Invalid flash comp type
|
||||
*/
|
||||
enum iosm_flash_comp_type {
|
||||
FLASH_COMP_TYPE_PSI,
|
||||
FLASH_COMP_TYPE_EBL,
|
||||
FLASH_COMP_TYPE_FLS,
|
||||
FLASH_COMP_TYPE_INVAL,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_devlink_sio - SIO instance
|
||||
* @rx_list: Downlink skbuf list received from CP
|
||||
* @read_sem: Needed for the blocking read or downlink transfer
|
||||
* @channel_id: Reserved channel id for flashing/CD collection to RAM
|
||||
* @channel: Channel instance for flashing and coredump
|
||||
* @devlink_read_pend: Check if read is pending
|
||||
*/
|
||||
struct iosm_devlink_sio {
|
||||
struct sk_buff_head rx_list;
|
||||
struct completion read_sem;
|
||||
int channel_id;
|
||||
struct ipc_mem_channel *channel;
|
||||
u32 devlink_read_pend;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_flash_params - List of flash params required for flashing
|
||||
* @address: Address of the region file to be flashed
|
||||
* @region_count: Maximum no of regions for each fls file
|
||||
* @download_region: To be set if region is being flashed
|
||||
* @erase_full_flash: To set the flashing mode
|
||||
* erase_full_flash = 1; full erase
|
||||
* erase_full_flash = 0; no erase
|
||||
* @erase_full_flash_done: Flag to check if it is a full erase
|
||||
*/
|
||||
struct iosm_flash_params {
|
||||
u32 address;
|
||||
u8 region_count;
|
||||
u8 download_region;
|
||||
u8 erase_full_flash;
|
||||
u8 erase_full_flash_done;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_ebl_ctx_data - EBL ctx data used during flashing
|
||||
* @ebl_sw_info_version: SWID version info obtained from EBL
|
||||
* @m_ebl_resp: Buffer used to read and write the ebl data
|
||||
*/
|
||||
struct iosm_ebl_ctx_data {
|
||||
u8 ebl_sw_info_version;
|
||||
u8 m_ebl_resp[IOSM_EBL_RSP_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_coredump_file_info - Coredump file info
|
||||
* @filename: Name of coredump file
|
||||
* @default_size: Default size of coredump file
|
||||
* @actual_size: Actual size of coredump file
|
||||
* @entry: Index of the coredump file
|
||||
*/
|
||||
struct iosm_coredump_file_info {
|
||||
char filename[IOSM_MAX_FILENAME_LEN];
|
||||
u32 default_size;
|
||||
u32 actual_size;
|
||||
u32 entry;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_devlink - IOSM Devlink structure
|
||||
* @devlink_sio: SIO instance for read/write functionality
|
||||
* @pcie: Pointer to PCIe component
|
||||
* @dev: Pointer to device struct
|
||||
* @devlink_ctx: Pointer to devlink context
|
||||
* @param: Params required for flashing
|
||||
* @ebl_ctx: Data to be read and written to Modem
|
||||
* @cd_file_info: coredump file info
|
||||
* @iosm_devlink_mdm_coredump: region ops for coredump collection
|
||||
* @cd_regions: coredump regions
|
||||
*/
|
||||
struct iosm_devlink {
|
||||
struct iosm_devlink_sio devlink_sio;
|
||||
struct iosm_pcie *pcie;
|
||||
struct device *dev;
|
||||
struct devlink *devlink_ctx;
|
||||
struct iosm_flash_params param;
|
||||
struct iosm_ebl_ctx_data ebl_ctx;
|
||||
struct iosm_coredump_file_info *cd_file_info;
|
||||
struct devlink_region_ops iosm_devlink_mdm_coredump[IOSM_NOF_CD_REGION];
|
||||
struct devlink_region *cd_regions[IOSM_NOF_CD_REGION];
|
||||
};
|
||||
|
||||
/**
|
||||
* union iosm_rpsi_param_u - RPSI cmd param for CRC calculation
|
||||
* @word: Words member used in CRC calculation
|
||||
* @dword: Actual data
|
||||
*/
|
||||
union iosm_rpsi_param_u {
|
||||
__le16 word[2];
|
||||
__le32 dword;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_rpsi_cmd - Structure for RPSI Command
|
||||
* @param: Used to calculate CRC
|
||||
* @cmd: Stores the RPSI command
|
||||
* @crc: Stores the CRC value
|
||||
*/
|
||||
struct iosm_rpsi_cmd {
|
||||
union iosm_rpsi_param_u param;
|
||||
__le16 cmd;
|
||||
__le16 crc;
|
||||
};
|
||||
|
||||
/**
|
||||
* ipc_devlink_init - To initialize the devlink to IOSM driver
|
||||
* @ipc_imem: Pointer to struct iosm_imem
|
||||
*
|
||||
* Returns: Pointer to iosm_devlink on success and NULL on failure
|
||||
*/
|
||||
struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem);
|
||||
|
||||
/**
|
||||
* ipc_devlink_deinit - To unintialize the devlink from IOSM driver.
|
||||
* @ipc_devlink: Devlink instance
|
||||
*/
|
||||
void ipc_devlink_deinit(struct iosm_devlink *ipc_devlink);
|
||||
|
||||
/**
|
||||
* ipc_devlink_send_cmd - Send command to Modem
|
||||
* @ipc_devlink: Pointer to struct iosm_devlink
|
||||
* @cmd: Command to be sent to modem
|
||||
* @entry: Command entry number
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_devlink_send_cmd(struct iosm_devlink *ipc_devlink, u16 cmd, u32 entry);
|
||||
|
||||
#endif /* _IOSM_IPC_DEVLINK_H */
|
||||
562
drivers/net/wwan/iosm/iosm_ipc_flash.c
Normal file
562
drivers/net/wwan/iosm/iosm_ipc_flash.c
Normal file
@@ -0,0 +1,562 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include "iosm_ipc_coredump.h"
|
||||
#include "iosm_ipc_devlink.h"
|
||||
#include "iosm_ipc_flash.h"
|
||||
|
||||
/* This function will pack the data to be sent to the modem using the
|
||||
* payload, payload length and pack id
|
||||
*/
|
||||
static int ipc_flash_proc_format_ebl_pack(struct iosm_flash_data *flash_req,
|
||||
u32 pack_length, u16 pack_id,
|
||||
u8 *payload, u32 payload_length)
|
||||
{
|
||||
u16 checksum = pack_id;
|
||||
u32 i;
|
||||
|
||||
if (payload_length + IOSM_EBL_HEAD_SIZE > pack_length)
|
||||
return -EINVAL;
|
||||
|
||||
flash_req->pack_id = cpu_to_le16(pack_id);
|
||||
flash_req->msg_length = cpu_to_le32(payload_length);
|
||||
checksum += (payload_length >> IOSM_EBL_PAYL_SHIFT) +
|
||||
(payload_length & IOSM_EBL_CKSM);
|
||||
|
||||
for (i = 0; i < payload_length; i++)
|
||||
checksum += payload[i];
|
||||
|
||||
flash_req->checksum = cpu_to_le16(checksum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* validate the response received from modem and
|
||||
* check the type of errors received
|
||||
*/
|
||||
static int ipc_flash_proc_check_ebl_rsp(void *hdr_rsp, void *payload_rsp)
|
||||
{
|
||||
struct iosm_ebl_error *err_info = payload_rsp;
|
||||
u16 *rsp_code = hdr_rsp;
|
||||
int res = 0;
|
||||
u32 i;
|
||||
|
||||
if (*rsp_code == IOSM_EBL_RSP_BUFF) {
|
||||
for (i = 0; i < IOSM_MAX_ERRORS; i++) {
|
||||
if (!err_info->error[i].error_code) {
|
||||
pr_err("EBL: error_class = %d, error_code = %d",
|
||||
err_info->error[i].error_class,
|
||||
err_info->error[i].error_code);
|
||||
}
|
||||
}
|
||||
res = -EINVAL;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Send data to the modem */
|
||||
static int ipc_flash_send_data(struct iosm_devlink *ipc_devlink, u32 size,
|
||||
u16 pack_id, u8 *payload, u32 payload_length)
|
||||
{
|
||||
struct iosm_flash_data flash_req;
|
||||
int ret;
|
||||
|
||||
ret = ipc_flash_proc_format_ebl_pack(&flash_req, size,
|
||||
pack_id, payload, payload_length);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL2 pack failed for pack_id:%d",
|
||||
pack_id);
|
||||
goto ipc_free_payload;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&flash_req,
|
||||
IOSM_EBL_HEAD_SIZE);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL Header write failed for Id:%x",
|
||||
pack_id);
|
||||
goto ipc_free_payload;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, payload, payload_length);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL Payload write failed for Id:%x",
|
||||
pack_id);
|
||||
}
|
||||
|
||||
ipc_free_payload:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Allocate flash channel and read LER data from modem */
|
||||
int ipc_flash_link_establish(struct iosm_imem *ipc_imem)
|
||||
{
|
||||
u8 ler_data[IOSM_LER_RSP_SIZE];
|
||||
u32 bytes_read;
|
||||
|
||||
/* Allocate channel for flashing/cd collection */
|
||||
ipc_imem->ipc_devlink->devlink_sio.channel =
|
||||
ipc_imem_sys_devlink_open(ipc_imem);
|
||||
|
||||
if (!ipc_imem->ipc_devlink->devlink_sio.channel)
|
||||
goto chl_open_fail;
|
||||
|
||||
if (ipc_imem_sys_devlink_read(ipc_imem->ipc_devlink, ler_data,
|
||||
IOSM_LER_RSP_SIZE, &bytes_read))
|
||||
goto devlink_read_fail;
|
||||
|
||||
if (bytes_read != IOSM_LER_RSP_SIZE)
|
||||
goto devlink_read_fail;
|
||||
return 0;
|
||||
|
||||
devlink_read_fail:
|
||||
ipc_imem_sys_devlink_close(ipc_imem->ipc_devlink);
|
||||
chl_open_fail:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Receive data from the modem */
|
||||
static int ipc_flash_receive_data(struct iosm_devlink *ipc_devlink, u32 size,
|
||||
u8 *mdm_rsp)
|
||||
{
|
||||
u8 mdm_rsp_hdr[IOSM_EBL_HEAD_SIZE];
|
||||
u32 bytes_read;
|
||||
int ret;
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, mdm_rsp_hdr,
|
||||
IOSM_EBL_HEAD_SIZE, &bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL rsp to read %d bytes failed",
|
||||
IOSM_EBL_HEAD_SIZE);
|
||||
goto ipc_flash_recv_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_EBL_HEAD_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_recv_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, mdm_rsp, size,
|
||||
&bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL rsp to read %d bytes failed",
|
||||
size);
|
||||
goto ipc_flash_recv_err;
|
||||
}
|
||||
|
||||
if (bytes_read != size) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_recv_err;
|
||||
}
|
||||
|
||||
ret = ipc_flash_proc_check_ebl_rsp(mdm_rsp_hdr + 2, mdm_rsp);
|
||||
|
||||
ipc_flash_recv_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Function to send command to modem and receive response */
|
||||
static int ipc_flash_send_receive(struct iosm_devlink *ipc_devlink, u16 pack_id,
|
||||
u8 *payload, u32 payload_length, u8 *mdm_rsp)
|
||||
{
|
||||
size_t frame_len = IOSM_EBL_DW_PACK_SIZE;
|
||||
int ret;
|
||||
|
||||
if (pack_id == FLASH_SET_PROT_CONF)
|
||||
frame_len = IOSM_EBL_W_PACK_SIZE;
|
||||
|
||||
ret = ipc_flash_send_data(ipc_devlink, frame_len, pack_id, payload,
|
||||
payload_length);
|
||||
if (ret)
|
||||
goto ipc_flash_send_rcv;
|
||||
|
||||
ret = ipc_flash_receive_data(ipc_devlink,
|
||||
frame_len - IOSM_EBL_HEAD_SIZE, mdm_rsp);
|
||||
|
||||
ipc_flash_send_rcv:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the capabilities for the EBL */
|
||||
int ipc_flash_boot_set_capabilities(struct iosm_devlink *ipc_devlink,
|
||||
u8 *mdm_rsp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ipc_devlink->ebl_ctx.ebl_sw_info_version =
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_RSP_SW_INFO_VER];
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_SKIP_ERASE] = IOSM_CAP_NOT_ENHANCED;
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_SKIP_CRC] = IOSM_CAP_NOT_ENHANCED;
|
||||
|
||||
if (ipc_devlink->ebl_ctx.m_ebl_resp[EBL_CAPS_FLAG] &
|
||||
IOSM_CAP_USE_EXT_CAP) {
|
||||
if (ipc_devlink->param.erase_full_flash)
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_OOS_CONFIG] &=
|
||||
~((u8)IOSM_EXT_CAP_ERASE_ALL);
|
||||
else
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_OOS_CONFIG] &=
|
||||
~((u8)IOSM_EXT_CAP_COMMIT_ALL);
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_EXT_CAPS_HANDLED] =
|
||||
IOSM_CAP_USE_EXT_CAP;
|
||||
}
|
||||
|
||||
/* Write back the EBL capability to modem
|
||||
* Request Set Protcnf command
|
||||
*/
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SET_PROT_CONF,
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp,
|
||||
IOSM_EBL_RSP_SIZE, mdm_rsp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read the SWID type and SWID value from the EBL */
|
||||
int ipc_flash_read_swid(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
|
||||
{
|
||||
struct iosm_flash_msg_control cmd_msg;
|
||||
struct iosm_swid_table *swid;
|
||||
char ebl_swid[IOSM_SWID_STR];
|
||||
int ret;
|
||||
|
||||
if (ipc_devlink->ebl_ctx.ebl_sw_info_version !=
|
||||
IOSM_EXT_CAP_SWID_OOS_PACK)
|
||||
return -EINVAL;
|
||||
|
||||
cmd_msg.action = cpu_to_le32(FLASH_OOSC_ACTION_READ);
|
||||
cmd_msg.type = cpu_to_le32(FLASH_OOSC_TYPE_SWID_TABLE);
|
||||
cmd_msg.length = cpu_to_le32(IOSM_MSG_LEN_ARG);
|
||||
cmd_msg.arguments = cpu_to_le32(IOSM_MSG_LEN_ARG);
|
||||
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_CONTROL,
|
||||
(u8 *)&cmd_msg, IOSM_MDM_SEND_16, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_swid_err;
|
||||
|
||||
cmd_msg.action = cpu_to_le32(*((u32 *)mdm_rsp));
|
||||
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_DATA_READ,
|
||||
(u8 *)&cmd_msg, IOSM_MDM_SEND_4, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_swid_err;
|
||||
|
||||
swid = (struct iosm_swid_table *)mdm_rsp;
|
||||
dev_dbg(ipc_devlink->dev, "SWID %x RF_ENGINE_ID %x", swid->sw_id_val,
|
||||
swid->rf_engine_id_val);
|
||||
|
||||
snprintf(ebl_swid, sizeof(ebl_swid), "SWID: %x, RF_ENGINE_ID: %x",
|
||||
swid->sw_id_val, swid->rf_engine_id_val);
|
||||
|
||||
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx, ebl_swid,
|
||||
NULL, 0, 0);
|
||||
ipc_swid_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Function to check if full erase or conditional erase was successful */
|
||||
static int ipc_flash_erase_check(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
|
||||
{
|
||||
int ret, count = 0;
|
||||
u16 mdm_rsp_data;
|
||||
|
||||
/* Request Flash Erase Check */
|
||||
do {
|
||||
mdm_rsp_data = IOSM_MDM_SEND_DATA;
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_ERASE_CHECK,
|
||||
(u8 *)&mdm_rsp_data,
|
||||
IOSM_MDM_SEND_2, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_erase_chk_err;
|
||||
|
||||
mdm_rsp_data = *((u16 *)mdm_rsp);
|
||||
if (mdm_rsp_data > IOSM_MDM_ERASE_RSP) {
|
||||
dev_err(ipc_devlink->dev,
|
||||
"Flash Erase Check resp wrong 0x%04X",
|
||||
mdm_rsp_data);
|
||||
ret = -EINVAL;
|
||||
goto ipc_erase_chk_err;
|
||||
}
|
||||
count++;
|
||||
msleep(IOSM_FLASH_ERASE_CHECK_INTERVAL);
|
||||
} while ((mdm_rsp_data != IOSM_MDM_ERASE_RSP) &&
|
||||
(count < (IOSM_FLASH_ERASE_CHECK_TIMEOUT /
|
||||
IOSM_FLASH_ERASE_CHECK_INTERVAL)));
|
||||
|
||||
if (mdm_rsp_data != IOSM_MDM_ERASE_RSP) {
|
||||
dev_err(ipc_devlink->dev, "Modem erase check timeout failure!");
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
ipc_erase_chk_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Full erase function which will erase the nand flash through EBL command */
|
||||
static int ipc_flash_full_erase(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
|
||||
{
|
||||
u32 erase_address = IOSM_ERASE_START_ADDR;
|
||||
struct iosm_flash_msg_control cmd_msg;
|
||||
u32 erase_length = IOSM_ERASE_LEN;
|
||||
int ret;
|
||||
|
||||
dev_dbg(ipc_devlink->dev, "Erase full nand flash");
|
||||
cmd_msg.action = cpu_to_le32(FLASH_OOSC_ACTION_ERASE);
|
||||
cmd_msg.type = cpu_to_le32(FLASH_OOSC_TYPE_ALL_FLASH);
|
||||
cmd_msg.length = cpu_to_le32(erase_length);
|
||||
cmd_msg.arguments = cpu_to_le32(erase_address);
|
||||
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_CONTROL,
|
||||
(unsigned char *)&cmd_msg,
|
||||
IOSM_MDM_SEND_16, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_flash_erase_err;
|
||||
|
||||
ipc_devlink->param.erase_full_flash_done = IOSM_SET_FLAG;
|
||||
ret = ipc_flash_erase_check(ipc_devlink, mdm_rsp);
|
||||
|
||||
ipc_flash_erase_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Logic for flashing all the Loadmaps available for individual fls file */
|
||||
static int ipc_flash_download_region(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw, u8 *mdm_rsp)
|
||||
{
|
||||
__le32 reg_info[2]; /* 0th position region address, 1st position size */
|
||||
char *file_ptr;
|
||||
u32 rest_len;
|
||||
u32 raw_len;
|
||||
int ret;
|
||||
|
||||
file_ptr = (char *)fw->data;
|
||||
reg_info[0] = cpu_to_le32(ipc_devlink->param.address);
|
||||
|
||||
if (!ipc_devlink->param.erase_full_flash_done) {
|
||||
reg_info[1] = cpu_to_le32(ipc_devlink->param.address +
|
||||
fw->size - 2);
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_ERASE_START,
|
||||
(u8 *)reg_info, IOSM_MDM_SEND_8,
|
||||
mdm_rsp);
|
||||
if (ret)
|
||||
goto dl_region_fail;
|
||||
|
||||
ret = ipc_flash_erase_check(ipc_devlink, mdm_rsp);
|
||||
if (ret)
|
||||
goto dl_region_fail;
|
||||
}
|
||||
|
||||
/* Request Flash Set Address */
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SET_ADDRESS,
|
||||
(u8 *)reg_info, IOSM_MDM_SEND_4, mdm_rsp);
|
||||
if (ret)
|
||||
goto dl_region_fail;
|
||||
|
||||
rest_len = fw->size;
|
||||
|
||||
/* Request Flash Write Raw Image */
|
||||
ret = ipc_flash_send_data(ipc_devlink, IOSM_EBL_DW_PACK_SIZE,
|
||||
FLASH_WRITE_IMAGE_RAW, (u8 *)&rest_len,
|
||||
IOSM_MDM_SEND_4);
|
||||
if (ret)
|
||||
goto dl_region_fail;
|
||||
|
||||
do {
|
||||
raw_len = (rest_len > IOSM_FLS_BUF_SIZE) ? IOSM_FLS_BUF_SIZE :
|
||||
rest_len;
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, file_ptr,
|
||||
raw_len);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "Image write failed");
|
||||
goto dl_region_fail;
|
||||
}
|
||||
file_ptr += raw_len;
|
||||
rest_len -= raw_len;
|
||||
} while (rest_len);
|
||||
|
||||
ret = ipc_flash_receive_data(ipc_devlink, IOSM_EBL_DW_PAYL_SIZE,
|
||||
mdm_rsp);
|
||||
|
||||
dl_region_fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Flash the individual fls files */
|
||||
int ipc_flash_send_fls(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw, u8 *mdm_rsp)
|
||||
{
|
||||
u16 flash_cmd;
|
||||
int ret;
|
||||
|
||||
if (ipc_devlink->param.erase_full_flash) {
|
||||
ipc_devlink->param.erase_full_flash = false;
|
||||
ret = ipc_flash_full_erase(ipc_devlink, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_flash_err;
|
||||
}
|
||||
|
||||
/* Request Sec Start */
|
||||
if (!ipc_devlink->param.download_region) {
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SEC_START,
|
||||
(u8 *)fw->data, fw->size, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_flash_err;
|
||||
} else {
|
||||
/* Download regions */
|
||||
ipc_devlink->param.region_count -= IOSM_SET_FLAG;
|
||||
ret = ipc_flash_download_region(ipc_devlink, fw, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_flash_err;
|
||||
|
||||
if (!ipc_devlink->param.region_count) {
|
||||
/* Request Sec End */
|
||||
flash_cmd = IOSM_MDM_SEND_DATA;
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SEC_END,
|
||||
(u8 *)&flash_cmd,
|
||||
IOSM_MDM_SEND_2, mdm_rsp);
|
||||
}
|
||||
}
|
||||
|
||||
ipc_flash_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Inject RPSI */
|
||||
int ipc_flash_boot_psi(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
u8 psi_ack_byte[IOSM_PSI_ACK], read_data[2];
|
||||
u32 bytes_read;
|
||||
u8 *psi_code;
|
||||
int ret;
|
||||
|
||||
dev_dbg(ipc_devlink->dev, "Boot transfer PSI");
|
||||
psi_code = kzalloc(fw->size, GFP_KERNEL);
|
||||
if (!psi_code)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(psi_code, fw->data, fw->size);
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, psi_code, fw->size);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "RPSI Image write failed");
|
||||
goto ipc_flash_psi_free;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data,
|
||||
IOSM_LER_ACK_SIZE, &bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "ipc_devlink_sio_read ACK failed");
|
||||
goto ipc_flash_psi_free;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_LER_ACK_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_psi_free;
|
||||
}
|
||||
|
||||
snprintf(psi_ack_byte, sizeof(psi_ack_byte), "%x%x", read_data[0],
|
||||
read_data[1]);
|
||||
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx,
|
||||
psi_ack_byte, "PSI ACK", 0, 0);
|
||||
|
||||
if (read_data[0] == 0x00 && read_data[1] == 0xCD) {
|
||||
dev_dbg(ipc_devlink->dev, "Coredump detected");
|
||||
ret = ipc_coredump_get_list(ipc_devlink,
|
||||
rpsi_cmd_coredump_start);
|
||||
if (ret)
|
||||
dev_err(ipc_devlink->dev, "Failed to get cd list");
|
||||
}
|
||||
|
||||
ipc_flash_psi_free:
|
||||
kfree(psi_code);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Inject EBL */
|
||||
int ipc_flash_boot_ebl(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
u32 ebl_size = fw->size;
|
||||
u8 read_data[2];
|
||||
u32 bytes_read;
|
||||
int ret;
|
||||
|
||||
if (ipc_mmio_get_exec_stage(ipc_devlink->pcie->imem->mmio) !=
|
||||
IPC_MEM_EXEC_STAGE_PSI) {
|
||||
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx,
|
||||
"Invalid execution stage",
|
||||
NULL, 0, 0);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(ipc_devlink->dev, "Boot transfer EBL");
|
||||
ret = ipc_devlink_send_cmd(ipc_devlink, rpsi_cmd_code_ebl,
|
||||
IOSM_RPSI_LOAD_SIZE);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "Sending rpsi_cmd_code_ebl failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
|
||||
&bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "rpsi_cmd_code_ebl read failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_READ_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&ebl_size,
|
||||
sizeof(ebl_size));
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL length write failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
|
||||
&bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL read failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_READ_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, (unsigned char *)fw->data,
|
||||
fw->size);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL data transfer failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
|
||||
&bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL read failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_READ_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink,
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp,
|
||||
IOSM_EBL_RSP_SIZE, &bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL response read failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_EBL_RSP_SIZE)
|
||||
ret = -EINVAL;
|
||||
|
||||
ipc_flash_ebl_err:
|
||||
return ret;
|
||||
}
|
||||
271
drivers/net/wwan/iosm/iosm_ipc_flash.h
Normal file
271
drivers/net/wwan/iosm/iosm_ipc_flash.h
Normal file
@@ -0,0 +1,271 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2020-2021 Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef _IOSM_IPC_FLASH_H
|
||||
#define _IOSM_IPC_FLASH_H
|
||||
|
||||
/* Buffer size used to read the fls image */
|
||||
#define IOSM_FLS_BUF_SIZE 0x00100000
|
||||
/* Full erase start address */
|
||||
#define IOSM_ERASE_START_ADDR 0x00000000
|
||||
/* Erase length for NAND flash */
|
||||
#define IOSM_ERASE_LEN 0xFFFFFFFF
|
||||
/* EBL response Header size */
|
||||
#define IOSM_EBL_HEAD_SIZE 8
|
||||
/* EBL payload size */
|
||||
#define IOSM_EBL_W_PAYL_SIZE 2048
|
||||
/* Total EBL pack size */
|
||||
#define IOSM_EBL_W_PACK_SIZE (IOSM_EBL_HEAD_SIZE + IOSM_EBL_W_PAYL_SIZE)
|
||||
/* EBL payload size */
|
||||
#define IOSM_EBL_DW_PAYL_SIZE 16384
|
||||
/* Total EBL pack size */
|
||||
#define IOSM_EBL_DW_PACK_SIZE (IOSM_EBL_HEAD_SIZE + IOSM_EBL_DW_PAYL_SIZE)
|
||||
/* EBL name size */
|
||||
#define IOSM_EBL_NAME 32
|
||||
/* Maximum supported error types */
|
||||
#define IOSM_MAX_ERRORS 8
|
||||
/* Read size for RPSI/EBL response */
|
||||
#define IOSM_READ_SIZE 2
|
||||
/* Link establishment response ack size */
|
||||
#define IOSM_LER_ACK_SIZE 2
|
||||
/* PSI ACK len */
|
||||
#define IOSM_PSI_ACK 8
|
||||
/* SWID capability for packed swid type */
|
||||
#define IOSM_EXT_CAP_SWID_OOS_PACK 0x02
|
||||
/* EBL error response buffer */
|
||||
#define IOSM_EBL_RSP_BUFF 0x0041
|
||||
/* SWID string length */
|
||||
#define IOSM_SWID_STR 64
|
||||
/* Load EBL command size */
|
||||
#define IOSM_RPSI_LOAD_SIZE 0
|
||||
/* EBL payload checksum */
|
||||
#define IOSM_EBL_CKSM 0x0000FFFF
|
||||
/* SWID msg len and argument */
|
||||
#define IOSM_MSG_LEN_ARG 0
|
||||
/* Data to be sent to modem */
|
||||
#define IOSM_MDM_SEND_DATA 0x0000
|
||||
/* Data received from modem as part of erase check */
|
||||
#define IOSM_MDM_ERASE_RSP 0x0001
|
||||
/* Bit shift to calculate Checksum */
|
||||
#define IOSM_EBL_PAYL_SHIFT 16
|
||||
/* Flag To be set */
|
||||
#define IOSM_SET_FLAG 1
|
||||
/* Set flash erase check timeout to 100 msec */
|
||||
#define IOSM_FLASH_ERASE_CHECK_TIMEOUT 100
|
||||
/* Set flash erase check interval to 20 msec */
|
||||
#define IOSM_FLASH_ERASE_CHECK_INTERVAL 20
|
||||
/* Link establishment response ack size */
|
||||
#define IOSM_LER_RSP_SIZE 60
|
||||
|
||||
/**
|
||||
* enum iosm_flash_package_type - Enum for the flashing operations
|
||||
* @FLASH_SET_PROT_CONF: Write EBL capabilities
|
||||
* @FLASH_SEC_START: Start writing the secpack
|
||||
* @FLASH_SEC_END: Validate secpack end
|
||||
* @FLASH_SET_ADDRESS: Set the address for flashing
|
||||
* @FLASH_ERASE_START: Start erase before flashing
|
||||
* @FLASH_ERASE_CHECK: Validate the erase functionality
|
||||
* @FLASH_OOS_CONTROL: Retrieve data based on oos actions
|
||||
* @FLASH_OOS_DATA_READ: Read data from EBL
|
||||
* @FLASH_WRITE_IMAGE_RAW: Write the raw image to flash
|
||||
*/
|
||||
enum iosm_flash_package_type {
|
||||
FLASH_SET_PROT_CONF = 0x0086,
|
||||
FLASH_SEC_START = 0x0204,
|
||||
FLASH_SEC_END,
|
||||
FLASH_SET_ADDRESS = 0x0802,
|
||||
FLASH_ERASE_START = 0x0805,
|
||||
FLASH_ERASE_CHECK,
|
||||
FLASH_OOS_CONTROL = 0x080C,
|
||||
FLASH_OOS_DATA_READ = 0x080E,
|
||||
FLASH_WRITE_IMAGE_RAW,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_out_of_session_action - Actions possible over the
|
||||
* OutOfSession command interface
|
||||
* @FLASH_OOSC_ACTION_READ: Read data according to its type
|
||||
* @FLASH_OOSC_ACTION_ERASE: Erase data according to its type
|
||||
*/
|
||||
enum iosm_out_of_session_action {
|
||||
FLASH_OOSC_ACTION_READ = 2,
|
||||
FLASH_OOSC_ACTION_ERASE = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_out_of_session_type - Data types that can be handled over the
|
||||
* Out Of Session command Interface
|
||||
* @FLASH_OOSC_TYPE_ALL_FLASH: The whole flash area
|
||||
* @FLASH_OOSC_TYPE_SWID_TABLE: Read the swid table from the target
|
||||
*/
|
||||
enum iosm_out_of_session_type {
|
||||
FLASH_OOSC_TYPE_ALL_FLASH = 8,
|
||||
FLASH_OOSC_TYPE_SWID_TABLE = 16,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_ebl_caps - EBL capability settings
|
||||
* @IOSM_CAP_NOT_ENHANCED: If capability not supported
|
||||
* @IOSM_CAP_USE_EXT_CAP: To be set if extended capability is set
|
||||
* @IOSM_EXT_CAP_ERASE_ALL: Set Erase all capability
|
||||
* @IOSM_EXT_CAP_COMMIT_ALL: Set the commit all capability
|
||||
*/
|
||||
enum iosm_ebl_caps {
|
||||
IOSM_CAP_NOT_ENHANCED = 0x00,
|
||||
IOSM_CAP_USE_EXT_CAP = 0x01,
|
||||
IOSM_EXT_CAP_ERASE_ALL = 0x08,
|
||||
IOSM_EXT_CAP_COMMIT_ALL = 0x20,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_ebl_rsp - EBL response field
|
||||
* @EBL_CAPS_FLAG: EBL capability flag
|
||||
* @EBL_SKIP_ERASE: EBL skip erase flag
|
||||
* @EBL_SKIP_CRC: EBL skip wr_pack crc
|
||||
* @EBL_EXT_CAPS_HANDLED: EBL extended capability handled flag
|
||||
* @EBL_OOS_CONFIG: EBL oos configuration
|
||||
* @EBL_RSP_SW_INFO_VER: EBL SW info version
|
||||
*/
|
||||
enum iosm_ebl_rsp {
|
||||
EBL_CAPS_FLAG = 50,
|
||||
EBL_SKIP_ERASE = 54,
|
||||
EBL_SKIP_CRC = 55,
|
||||
EBL_EXT_CAPS_HANDLED = 57,
|
||||
EBL_OOS_CONFIG = 64,
|
||||
EBL_RSP_SW_INFO_VER = 70,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_mdm_send_recv_data - Data to send to modem
|
||||
* @IOSM_MDM_SEND_2: Send 2 bytes of payload
|
||||
* @IOSM_MDM_SEND_4: Send 4 bytes of payload
|
||||
* @IOSM_MDM_SEND_8: Send 8 bytes of payload
|
||||
* @IOSM_MDM_SEND_16: Send 16 bytes of payload
|
||||
*/
|
||||
enum iosm_mdm_send_recv_data {
|
||||
IOSM_MDM_SEND_2 = 2,
|
||||
IOSM_MDM_SEND_4 = 4,
|
||||
IOSM_MDM_SEND_8 = 8,
|
||||
IOSM_MDM_SEND_16 = 16,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_ebl_one_error - Structure containing error details
|
||||
* @error_class: Error type- standard, security and text error
|
||||
* @error_code: Specific error from error type
|
||||
*/
|
||||
struct iosm_ebl_one_error {
|
||||
u16 error_class;
|
||||
u16 error_code;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_ebl_error- Structure with max error type supported
|
||||
* @error: Array of one_error structure with max errors
|
||||
*/
|
||||
struct iosm_ebl_error {
|
||||
struct iosm_ebl_one_error error[IOSM_MAX_ERRORS];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_swid_table - SWID table data for modem
|
||||
* @number_of_data_sets: Number of swid types
|
||||
* @sw_id_type: SWID type - SWID
|
||||
* @sw_id_val: SWID value
|
||||
* @rf_engine_id_type: RF engine ID type - RF_ENGINE_ID
|
||||
* @rf_engine_id_val: RF engine ID value
|
||||
*/
|
||||
struct iosm_swid_table {
|
||||
u32 number_of_data_sets;
|
||||
char sw_id_type[IOSM_EBL_NAME];
|
||||
u32 sw_id_val;
|
||||
char rf_engine_id_type[IOSM_EBL_NAME];
|
||||
u32 rf_engine_id_val;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_flash_msg_control - Data sent to modem
|
||||
* @action: Action to be performed
|
||||
* @type: Type of action
|
||||
* @length: Length of the action
|
||||
* @arguments: Argument value sent to modem
|
||||
*/
|
||||
struct iosm_flash_msg_control {
|
||||
__le32 action;
|
||||
__le32 type;
|
||||
__le32 length;
|
||||
__le32 arguments;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_flash_data - Header Data to be sent to modem
|
||||
* @checksum: Checksum value calculated for the payload data
|
||||
* @pack_id: Flash Action type
|
||||
* @msg_length: Payload length
|
||||
*/
|
||||
struct iosm_flash_data {
|
||||
__le16 checksum;
|
||||
__le16 pack_id;
|
||||
__le32 msg_length;
|
||||
};
|
||||
|
||||
/**
|
||||
* ipc_flash_boot_psi - Inject PSI image
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @fw: FW image
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_boot_psi(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw);
|
||||
|
||||
/**
|
||||
* ipc_flash_boot_ebl - Inject EBL image
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @fw: FW image
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_boot_ebl(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw);
|
||||
|
||||
/**
|
||||
* ipc_flash_boot_set_capabilities - Set modem bool capabilities in flash
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @mdm_rsp: Pointer to modem response buffer
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_boot_set_capabilities(struct iosm_devlink *ipc_devlink,
|
||||
u8 *mdm_rsp);
|
||||
|
||||
/**
|
||||
* ipc_flash_link_establish - Flash link establishment
|
||||
* @ipc_imem: Pointer to struct iosm_imem
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_link_establish(struct iosm_imem *ipc_imem);
|
||||
|
||||
/**
|
||||
* ipc_flash_read_swid - Get swid during flash phase
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @mdm_rsp: Pointer to modem response buffer
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_read_swid(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp);
|
||||
|
||||
/**
|
||||
* ipc_flash_send_fls - Inject Modem subsystem fls file to device
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @fw: FW image
|
||||
* @mdm_rsp: Pointer to modem response buffer
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_send_fls(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw, u8 *mdm_rsp);
|
||||
#endif
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "iosm_ipc_chnl_cfg.h"
|
||||
#include "iosm_ipc_devlink.h"
|
||||
#include "iosm_ipc_flash.h"
|
||||
#include "iosm_ipc_imem.h"
|
||||
#include "iosm_ipc_port.h"
|
||||
|
||||
@@ -263,9 +265,12 @@ static void ipc_imem_dl_skb_process(struct iosm_imem *ipc_imem,
|
||||
switch (pipe->channel->ctype) {
|
||||
case IPC_CTYPE_CTRL:
|
||||
port_id = pipe->channel->channel_id;
|
||||
|
||||
/* Pass the packet to the wwan layer. */
|
||||
wwan_port_rx(ipc_imem->ipc_port[port_id]->iosm_port, skb);
|
||||
if (port_id == IPC_MEM_CTRL_CHL_ID_7)
|
||||
ipc_imem_sys_devlink_notify_rx(ipc_imem->ipc_devlink,
|
||||
skb);
|
||||
else
|
||||
wwan_port_rx(ipc_imem->ipc_port[port_id]->iosm_port,
|
||||
skb);
|
||||
break;
|
||||
|
||||
case IPC_CTYPE_WWAN:
|
||||
@@ -399,19 +404,8 @@ static void ipc_imem_rom_irq_exec(struct iosm_imem *ipc_imem)
|
||||
{
|
||||
struct ipc_mem_channel *channel;
|
||||
|
||||
if (ipc_imem->flash_channel_id < 0) {
|
||||
ipc_imem->rom_exit_code = IMEM_ROM_EXIT_FAIL;
|
||||
dev_err(ipc_imem->dev, "Missing flash app:%d",
|
||||
ipc_imem->flash_channel_id);
|
||||
return;
|
||||
}
|
||||
|
||||
channel = ipc_imem->ipc_devlink->devlink_sio.channel;
|
||||
ipc_imem->rom_exit_code = ipc_mmio_get_rom_exit_code(ipc_imem->mmio);
|
||||
|
||||
/* Wake up the flash app to continue or to terminate depending
|
||||
* on the CP ROM exit code.
|
||||
*/
|
||||
channel = &ipc_imem->channels[ipc_imem->flash_channel_id];
|
||||
complete(&channel->ul_sem);
|
||||
}
|
||||
|
||||
@@ -572,7 +566,7 @@ static void ipc_imem_handle_irq(struct iosm_imem *ipc_imem, int irq)
|
||||
enum ipc_phase old_phase, phase;
|
||||
bool retry_allocation = false;
|
||||
bool ul_pending = false;
|
||||
int ch_id, i;
|
||||
int i;
|
||||
|
||||
if (irq != IMEM_IRQ_DONT_CARE)
|
||||
ipc_imem->ev_irq_pending[irq] = false;
|
||||
@@ -696,11 +690,8 @@ static void ipc_imem_handle_irq(struct iosm_imem *ipc_imem, int irq)
|
||||
if ((phase == IPC_P_PSI || phase == IPC_P_EBL) &&
|
||||
ipc_imem->ipc_requested_state == IPC_MEM_DEVICE_IPC_RUNNING &&
|
||||
ipc_mmio_get_ipc_state(ipc_imem->mmio) ==
|
||||
IPC_MEM_DEVICE_IPC_RUNNING &&
|
||||
ipc_imem->flash_channel_id >= 0) {
|
||||
/* Wake up the flash app to open the pipes. */
|
||||
ch_id = ipc_imem->flash_channel_id;
|
||||
complete(&ipc_imem->channels[ch_id].ul_sem);
|
||||
IPC_MEM_DEVICE_IPC_RUNNING) {
|
||||
complete(&ipc_imem->ipc_devlink->devlink_sio.channel->ul_sem);
|
||||
}
|
||||
|
||||
/* Reset the expected CP state. */
|
||||
@@ -1176,6 +1167,9 @@ void ipc_imem_cleanup(struct iosm_imem *ipc_imem)
|
||||
ipc_port_deinit(ipc_imem->ipc_port);
|
||||
}
|
||||
|
||||
if (ipc_imem->ipc_devlink)
|
||||
ipc_devlink_deinit(ipc_imem->ipc_devlink);
|
||||
|
||||
ipc_imem_device_ipc_uninit(ipc_imem);
|
||||
ipc_imem_channel_reset(ipc_imem);
|
||||
|
||||
@@ -1258,6 +1252,7 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
|
||||
void __iomem *mmio, struct device *dev)
|
||||
{
|
||||
struct iosm_imem *ipc_imem = kzalloc(sizeof(*pcie->imem), GFP_KERNEL);
|
||||
enum ipc_mem_exec_stage stage;
|
||||
|
||||
if (!ipc_imem)
|
||||
return NULL;
|
||||
@@ -1272,9 +1267,6 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
|
||||
ipc_imem->cp_version = 0;
|
||||
ipc_imem->device_sleep = IPC_HOST_SLEEP_ENTER_SLEEP;
|
||||
|
||||
/* Reset the flash channel id. */
|
||||
ipc_imem->flash_channel_id = -1;
|
||||
|
||||
/* Reset the max number of configured channels */
|
||||
ipc_imem->nr_of_channels = 0;
|
||||
|
||||
@@ -1328,8 +1320,21 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
|
||||
goto imem_config_fail;
|
||||
}
|
||||
|
||||
return ipc_imem;
|
||||
stage = ipc_mmio_get_exec_stage(ipc_imem->mmio);
|
||||
if (stage == IPC_MEM_EXEC_STAGE_BOOT) {
|
||||
/* Alloc and Register devlink */
|
||||
ipc_imem->ipc_devlink = ipc_devlink_init(ipc_imem);
|
||||
if (!ipc_imem->ipc_devlink) {
|
||||
dev_err(ipc_imem->dev, "Devlink register failed");
|
||||
goto imem_config_fail;
|
||||
}
|
||||
|
||||
if (ipc_flash_link_establish(ipc_imem))
|
||||
goto devlink_channel_fail;
|
||||
}
|
||||
return ipc_imem;
|
||||
devlink_channel_fail:
|
||||
ipc_devlink_deinit(ipc_imem->ipc_devlink);
|
||||
imem_config_fail:
|
||||
hrtimer_cancel(&ipc_imem->td_alloc_timer);
|
||||
hrtimer_cancel(&ipc_imem->fast_update_timer);
|
||||
@@ -1361,3 +1366,51 @@ void ipc_imem_td_update_timer_suspend(struct iosm_imem *ipc_imem, bool suspend)
|
||||
{
|
||||
ipc_imem->td_update_timer_suspended = suspend;
|
||||
}
|
||||
|
||||
/* Verify the CP execution state, copy the chip info,
|
||||
* change the execution phase to ROM
|
||||
*/
|
||||
static int ipc_imem_devlink_trigger_chip_info_cb(struct iosm_imem *ipc_imem,
|
||||
int arg, void *msg,
|
||||
size_t msgsize)
|
||||
{
|
||||
enum ipc_mem_exec_stage stage;
|
||||
struct sk_buff *skb;
|
||||
int rc = -EINVAL;
|
||||
size_t size;
|
||||
|
||||
/* Test the CP execution state. */
|
||||
stage = ipc_mmio_get_exec_stage(ipc_imem->mmio);
|
||||
if (stage != IPC_MEM_EXEC_STAGE_BOOT) {
|
||||
dev_err(ipc_imem->dev,
|
||||
"Execution_stage: expected BOOT, received = %X", stage);
|
||||
goto trigger_chip_info_fail;
|
||||
}
|
||||
/* Allocate a new sk buf for the chip info. */
|
||||
size = ipc_imem->mmio->chip_info_size;
|
||||
if (size > IOSM_CHIP_INFO_SIZE_MAX)
|
||||
goto trigger_chip_info_fail;
|
||||
|
||||
skb = ipc_pcie_alloc_local_skb(ipc_imem->pcie, GFP_ATOMIC, size);
|
||||
if (!skb) {
|
||||
dev_err(ipc_imem->dev, "exhausted skbuf kernel DL memory");
|
||||
rc = -ENOMEM;
|
||||
goto trigger_chip_info_fail;
|
||||
}
|
||||
/* Copy the chip info characters into the ipc_skb. */
|
||||
ipc_mmio_copy_chip_info(ipc_imem->mmio, skb_put(skb, size), size);
|
||||
/* First change to the ROM boot phase. */
|
||||
dev_dbg(ipc_imem->dev, "execution_stage[%X] eq. BOOT", stage);
|
||||
ipc_imem->phase = ipc_imem_phase_update(ipc_imem);
|
||||
ipc_imem_sys_devlink_notify_rx(ipc_imem->ipc_devlink, skb);
|
||||
rc = 0;
|
||||
trigger_chip_info_fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ipc_imem_devlink_trigger_chip_info(struct iosm_imem *ipc_imem)
|
||||
{
|
||||
return ipc_task_queue_send_task(ipc_imem,
|
||||
ipc_imem_devlink_trigger_chip_info_cb,
|
||||
0, NULL, 0, true);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ struct ipc_chnl_cfg;
|
||||
|
||||
#define IMEM_IRQ_DONT_CARE (-1)
|
||||
|
||||
#define IPC_MEM_MAX_CHANNELS 7
|
||||
#define IPC_MEM_MAX_CHANNELS 8
|
||||
|
||||
#define IPC_MEM_MUX_IP_SESSION_ENTRIES 8
|
||||
|
||||
@@ -98,6 +98,7 @@ struct ipc_chnl_cfg;
|
||||
#define IPC_MEM_DL_ETH_OFFSET 16
|
||||
|
||||
#define IPC_CB(skb) ((struct ipc_skb_cb *)((skb)->cb))
|
||||
#define IOSM_CHIP_INFO_SIZE_MAX 100
|
||||
|
||||
#define FULLY_FUNCTIONAL 0
|
||||
|
||||
@@ -304,9 +305,9 @@ enum ipc_phase {
|
||||
* @ipc_port: IPC PORT data structure pointer
|
||||
* @pcie: IPC PCIe
|
||||
* @dev: Pointer to device structure
|
||||
* @flash_channel_id: Reserved channel id for flashing to RAM.
|
||||
* @ipc_requested_state: Expected IPC state on CP.
|
||||
* @channels: Channel list with UL/DL pipe pairs.
|
||||
* @ipc_devlink: IPC Devlink data structure pointer
|
||||
* @ipc_status: local ipc_status
|
||||
* @nr_of_channels: number of configured channels
|
||||
* @startup_timer: startup timer for NAND support.
|
||||
@@ -349,9 +350,9 @@ struct iosm_imem {
|
||||
struct iosm_cdev *ipc_port[IPC_MEM_MAX_CHANNELS];
|
||||
struct iosm_pcie *pcie;
|
||||
struct device *dev;
|
||||
int flash_channel_id;
|
||||
enum ipc_mem_device_ipc_state ipc_requested_state;
|
||||
struct ipc_mem_channel channels[IPC_MEM_MAX_CHANNELS];
|
||||
struct iosm_devlink *ipc_devlink;
|
||||
u32 ipc_status;
|
||||
u32 nr_of_channels;
|
||||
struct hrtimer startup_timer;
|
||||
@@ -575,4 +576,15 @@ void ipc_imem_ipc_init_check(struct iosm_imem *ipc_imem);
|
||||
*/
|
||||
void ipc_imem_channel_init(struct iosm_imem *ipc_imem, enum ipc_ctype ctype,
|
||||
struct ipc_chnl_cfg chnl_cfg, u32 irq_moderation);
|
||||
|
||||
/**
|
||||
* ipc_imem_devlink_trigger_chip_info - Inform devlink that the chip
|
||||
* information are available if the
|
||||
* flashing to RAM interworking shall be
|
||||
* executed.
|
||||
* @ipc_imem: Pointer to imem structure
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int ipc_imem_devlink_trigger_chip_info(struct iosm_imem *ipc_imem);
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "iosm_ipc_chnl_cfg.h"
|
||||
#include "iosm_ipc_devlink.h"
|
||||
#include "iosm_ipc_imem.h"
|
||||
#include "iosm_ipc_imem_ops.h"
|
||||
#include "iosm_ipc_port.h"
|
||||
@@ -331,3 +332,319 @@ int ipc_imem_sys_cdev_write(struct iosm_cdev *ipc_cdev, struct sk_buff *skb)
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Open a SIO link to CP and return the channel instance */
|
||||
struct ipc_mem_channel *ipc_imem_sys_devlink_open(struct iosm_imem *ipc_imem)
|
||||
{
|
||||
struct ipc_mem_channel *channel;
|
||||
enum ipc_phase phase;
|
||||
int channel_id;
|
||||
|
||||
phase = ipc_imem_phase_update(ipc_imem);
|
||||
switch (phase) {
|
||||
case IPC_P_OFF:
|
||||
case IPC_P_ROM:
|
||||
/* Get a channel id as flash id and reserve it. */
|
||||
channel_id = ipc_imem_channel_alloc(ipc_imem,
|
||||
IPC_MEM_CTRL_CHL_ID_7,
|
||||
IPC_CTYPE_CTRL);
|
||||
|
||||
if (channel_id < 0) {
|
||||
dev_err(ipc_imem->dev,
|
||||
"reservation of a flash channel id failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ipc_imem->ipc_devlink->devlink_sio.channel_id = channel_id;
|
||||
channel = &ipc_imem->channels[channel_id];
|
||||
|
||||
/* Enqueue chip info data to be read */
|
||||
if (ipc_imem_devlink_trigger_chip_info(ipc_imem)) {
|
||||
dev_err(ipc_imem->dev, "Enqueue of chip info failed");
|
||||
channel->state = IMEM_CHANNEL_FREE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return channel;
|
||||
|
||||
case IPC_P_PSI:
|
||||
case IPC_P_EBL:
|
||||
ipc_imem->cp_version = ipc_mmio_get_cp_version(ipc_imem->mmio);
|
||||
if (ipc_imem->cp_version == -1) {
|
||||
dev_err(ipc_imem->dev, "invalid CP version");
|
||||
goto error;
|
||||
}
|
||||
|
||||
channel_id = ipc_imem->ipc_devlink->devlink_sio.channel_id;
|
||||
return ipc_imem_channel_open(ipc_imem, channel_id,
|
||||
IPC_HP_CDEV_OPEN);
|
||||
|
||||
default:
|
||||
/* CP is in the wrong state (e.g. CRASH or CD_READY) */
|
||||
dev_err(ipc_imem->dev, "SIO open refused, phase %d", phase);
|
||||
}
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Release a SIO channel link to CP. */
|
||||
void ipc_imem_sys_devlink_close(struct iosm_devlink *ipc_devlink)
|
||||
{
|
||||
struct iosm_imem *ipc_imem = ipc_devlink->pcie->imem;
|
||||
int boot_check_timeout = BOOT_CHECK_DEFAULT_TIMEOUT;
|
||||
enum ipc_mem_exec_stage exec_stage;
|
||||
struct ipc_mem_channel *channel;
|
||||
enum ipc_phase curr_phase;
|
||||
int status = 0;
|
||||
u32 tail = 0;
|
||||
|
||||
channel = ipc_imem->ipc_devlink->devlink_sio.channel;
|
||||
curr_phase = ipc_imem->phase;
|
||||
/* Increase the total wait time to boot_check_timeout */
|
||||
do {
|
||||
exec_stage = ipc_mmio_get_exec_stage(ipc_imem->mmio);
|
||||
if (exec_stage == IPC_MEM_EXEC_STAGE_RUN ||
|
||||
exec_stage == IPC_MEM_EXEC_STAGE_PSI)
|
||||
break;
|
||||
msleep(20);
|
||||
boot_check_timeout -= 20;
|
||||
} while (boot_check_timeout > 0);
|
||||
|
||||
/* If there are any pending TDs then wait for Timeout/Completion before
|
||||
* closing pipe.
|
||||
*/
|
||||
if (channel->ul_pipe.old_tail != channel->ul_pipe.old_head) {
|
||||
status = wait_for_completion_interruptible_timeout
|
||||
(&ipc_imem->ul_pend_sem,
|
||||
msecs_to_jiffies(IPC_PEND_DATA_TIMEOUT));
|
||||
if (status == 0) {
|
||||
dev_dbg(ipc_imem->dev,
|
||||
"Data Timeout on UL-Pipe:%d Head:%d Tail:%d",
|
||||
channel->ul_pipe.pipe_nr,
|
||||
channel->ul_pipe.old_head,
|
||||
channel->ul_pipe.old_tail);
|
||||
}
|
||||
}
|
||||
|
||||
ipc_protocol_get_head_tail_index(ipc_imem->ipc_protocol,
|
||||
&channel->dl_pipe, NULL, &tail);
|
||||
|
||||
if (tail != channel->dl_pipe.old_tail) {
|
||||
status = wait_for_completion_interruptible_timeout
|
||||
(&ipc_imem->dl_pend_sem,
|
||||
msecs_to_jiffies(IPC_PEND_DATA_TIMEOUT));
|
||||
if (status == 0) {
|
||||
dev_dbg(ipc_imem->dev,
|
||||
"Data Timeout on DL-Pipe:%d Head:%d Tail:%d",
|
||||
channel->dl_pipe.pipe_nr,
|
||||
channel->dl_pipe.old_head,
|
||||
channel->dl_pipe.old_tail);
|
||||
}
|
||||
}
|
||||
|
||||
/* Due to wait for completion in messages, there is a small window
|
||||
* between closing the pipe and updating the channel is closed. In this
|
||||
* small window there could be HP update from Host Driver. Hence update
|
||||
* the channel state as CLOSING to aviod unnecessary interrupt
|
||||
* towards CP.
|
||||
*/
|
||||
channel->state = IMEM_CHANNEL_CLOSING;
|
||||
/* Release the pipe resources */
|
||||
ipc_imem_pipe_cleanup(ipc_imem, &channel->ul_pipe);
|
||||
ipc_imem_pipe_cleanup(ipc_imem, &channel->dl_pipe);
|
||||
}
|
||||
|
||||
void ipc_imem_sys_devlink_notify_rx(struct iosm_devlink *ipc_devlink,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
skb_queue_tail(&ipc_devlink->devlink_sio.rx_list, skb);
|
||||
complete(&ipc_devlink->devlink_sio.read_sem);
|
||||
}
|
||||
|
||||
/* PSI transfer */
|
||||
static int ipc_imem_sys_psi_transfer(struct iosm_imem *ipc_imem,
|
||||
struct ipc_mem_channel *channel,
|
||||
unsigned char *buf, int count)
|
||||
{
|
||||
int psi_start_timeout = PSI_START_DEFAULT_TIMEOUT;
|
||||
enum ipc_mem_exec_stage exec_stage;
|
||||
|
||||
dma_addr_t mapping = 0;
|
||||
int ret;
|
||||
|
||||
ret = ipc_pcie_addr_map(ipc_imem->pcie, buf, count, &mapping,
|
||||
DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
goto pcie_addr_map_fail;
|
||||
|
||||
/* Save the PSI information for the CP ROM driver on the doorbell
|
||||
* scratchpad.
|
||||
*/
|
||||
ipc_mmio_set_psi_addr_and_size(ipc_imem->mmio, mapping, count);
|
||||
ipc_doorbell_fire(ipc_imem->pcie, 0, IPC_MEM_EXEC_STAGE_BOOT);
|
||||
|
||||
ret = wait_for_completion_interruptible_timeout
|
||||
(&channel->ul_sem,
|
||||
msecs_to_jiffies(IPC_PSI_TRANSFER_TIMEOUT));
|
||||
|
||||
if (ret <= 0) {
|
||||
dev_err(ipc_imem->dev, "Failed PSI transfer to CP, Error-%d",
|
||||
ret);
|
||||
goto psi_transfer_fail;
|
||||
}
|
||||
/* If the PSI download fails, return the CP boot ROM exit code */
|
||||
if (ipc_imem->rom_exit_code != IMEM_ROM_EXIT_OPEN_EXT &&
|
||||
ipc_imem->rom_exit_code != IMEM_ROM_EXIT_CERT_EXT) {
|
||||
ret = (-1) * ((int)ipc_imem->rom_exit_code);
|
||||
goto psi_transfer_fail;
|
||||
}
|
||||
|
||||
dev_dbg(ipc_imem->dev, "PSI image successfully downloaded");
|
||||
|
||||
/* Wait psi_start_timeout milliseconds until the CP PSI image is
|
||||
* running and updates the execution_stage field with
|
||||
* IPC_MEM_EXEC_STAGE_PSI. Verify the execution stage.
|
||||
*/
|
||||
do {
|
||||
exec_stage = ipc_mmio_get_exec_stage(ipc_imem->mmio);
|
||||
|
||||
if (exec_stage == IPC_MEM_EXEC_STAGE_PSI)
|
||||
break;
|
||||
|
||||
msleep(20);
|
||||
psi_start_timeout -= 20;
|
||||
} while (psi_start_timeout > 0);
|
||||
|
||||
if (exec_stage != IPC_MEM_EXEC_STAGE_PSI)
|
||||
goto psi_transfer_fail; /* Unknown status of CP PSI process. */
|
||||
|
||||
ipc_imem->phase = IPC_P_PSI;
|
||||
|
||||
/* Enter the PSI phase. */
|
||||
dev_dbg(ipc_imem->dev, "execution_stage[%X] eq. PSI", exec_stage);
|
||||
|
||||
/* Request the RUNNING state from CP and wait until it was reached
|
||||
* or timeout.
|
||||
*/
|
||||
ipc_imem_ipc_init_check(ipc_imem);
|
||||
|
||||
ret = wait_for_completion_interruptible_timeout
|
||||
(&channel->ul_sem, msecs_to_jiffies(IPC_PSI_TRANSFER_TIMEOUT));
|
||||
if (ret <= 0) {
|
||||
dev_err(ipc_imem->dev,
|
||||
"Failed PSI RUNNING state on CP, Error-%d", ret);
|
||||
goto psi_transfer_fail;
|
||||
}
|
||||
|
||||
if (ipc_mmio_get_ipc_state(ipc_imem->mmio) !=
|
||||
IPC_MEM_DEVICE_IPC_RUNNING) {
|
||||
dev_err(ipc_imem->dev,
|
||||
"ch[%d] %s: unexpected CP IPC state %d, not RUNNING",
|
||||
channel->channel_id,
|
||||
ipc_imem_phase_get_string(ipc_imem->phase),
|
||||
ipc_mmio_get_ipc_state(ipc_imem->mmio));
|
||||
|
||||
goto psi_transfer_fail;
|
||||
}
|
||||
|
||||
/* Create the flash channel for the transfer of the images. */
|
||||
if (!ipc_imem_sys_devlink_open(ipc_imem)) {
|
||||
dev_err(ipc_imem->dev, "can't open flash_channel");
|
||||
goto psi_transfer_fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
psi_transfer_fail:
|
||||
ipc_pcie_addr_unmap(ipc_imem->pcie, count, mapping, DMA_TO_DEVICE);
|
||||
pcie_addr_map_fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ipc_imem_sys_devlink_write(struct iosm_devlink *ipc_devlink,
|
||||
unsigned char *buf, int count)
|
||||
{
|
||||
struct iosm_imem *ipc_imem = ipc_devlink->pcie->imem;
|
||||
struct ipc_mem_channel *channel;
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t mapping;
|
||||
int ret;
|
||||
|
||||
channel = ipc_imem->ipc_devlink->devlink_sio.channel;
|
||||
|
||||
/* In the ROM phase the PSI image is passed to CP about a specific
|
||||
* shared memory area and doorbell scratchpad directly.
|
||||
*/
|
||||
if (ipc_imem->phase == IPC_P_ROM) {
|
||||
ret = ipc_imem_sys_psi_transfer(ipc_imem, channel, buf, count);
|
||||
/* If the PSI transfer fails then send crash
|
||||
* Signature.
|
||||
*/
|
||||
if (ret > 0)
|
||||
ipc_imem_msg_send_feature_set(ipc_imem,
|
||||
IPC_MEM_INBAND_CRASH_SIG,
|
||||
false);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Allocate skb memory for the uplink buffer. */
|
||||
skb = ipc_pcie_alloc_skb(ipc_devlink->pcie, count, GFP_KERNEL, &mapping,
|
||||
DMA_TO_DEVICE, 0);
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(skb_put(skb, count), buf, count);
|
||||
|
||||
IPC_CB(skb)->op_type = UL_USR_OP_BLOCKED;
|
||||
|
||||
/* Add skb to the uplink skbuf accumulator. */
|
||||
skb_queue_tail(&channel->ul_list, skb);
|
||||
|
||||
/* Inform the IPC tasklet to pass uplink IP packets to CP. */
|
||||
if (!ipc_imem_call_cdev_write(ipc_imem)) {
|
||||
ret = wait_for_completion_interruptible(&channel->ul_sem);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(ipc_imem->dev,
|
||||
"ch[%d] no CP confirmation, status = %d",
|
||||
channel->channel_id, ret);
|
||||
ipc_pcie_kfree_skb(ipc_devlink->pcie, skb);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ipc_imem_sys_devlink_read(struct iosm_devlink *devlink, u8 *data,
|
||||
u32 bytes_to_read, u32 *bytes_read)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
int rc = 0;
|
||||
|
||||
/* check skb is available in rx_list or wait for skb */
|
||||
devlink->devlink_sio.devlink_read_pend = 1;
|
||||
while (!skb && !(skb = skb_dequeue(&devlink->devlink_sio.rx_list))) {
|
||||
if (!wait_for_completion_interruptible_timeout
|
||||
(&devlink->devlink_sio.read_sem,
|
||||
msecs_to_jiffies(IPC_READ_TIMEOUT))) {
|
||||
dev_err(devlink->dev, "Read timedout");
|
||||
rc = -ETIMEDOUT;
|
||||
goto devlink_read_fail;
|
||||
}
|
||||
}
|
||||
devlink->devlink_sio.devlink_read_pend = 0;
|
||||
if (bytes_to_read < skb->len) {
|
||||
dev_err(devlink->dev, "Invalid size,expected len %d", skb->len);
|
||||
rc = -EINVAL;
|
||||
goto devlink_read_fail;
|
||||
}
|
||||
*bytes_read = skb->len;
|
||||
memcpy(data, skb->data, skb->len);
|
||||
|
||||
devlink_read_fail:
|
||||
ipc_pcie_kfree_skb(devlink->pcie, skb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "iosm_ipc_mux_codec.h"
|
||||
|
||||
/* Maximum wait time for blocking read */
|
||||
#define IPC_READ_TIMEOUT 500
|
||||
#define IPC_READ_TIMEOUT 3000
|
||||
|
||||
/* The delay in ms for defering the unregister */
|
||||
#define SIO_UNREGISTER_DEFER_DELAY_MS 1
|
||||
@@ -98,4 +98,51 @@ int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem, int if_id,
|
||||
*/
|
||||
void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
|
||||
enum ipc_mux_protocol mux_type);
|
||||
|
||||
/**
|
||||
* ipc_imem_sys_devlink_open - Open a Flash/CD Channel link to CP
|
||||
* @ipc_imem: iosm_imem instance
|
||||
*
|
||||
* Return: channel instance on success, NULL for failure
|
||||
*/
|
||||
struct ipc_mem_channel *ipc_imem_sys_devlink_open(struct iosm_imem *ipc_imem);
|
||||
|
||||
/**
|
||||
* ipc_imem_sys_devlink_close - Release a Flash/CD channel link to CP
|
||||
* @ipc_devlink: Pointer to ipc_devlink data-struct
|
||||
*
|
||||
*/
|
||||
void ipc_imem_sys_devlink_close(struct iosm_devlink *ipc_devlink);
|
||||
|
||||
/**
|
||||
* ipc_imem_sys_devlink_notify_rx - Receive downlink characters from CP,
|
||||
* the downlink skbuf is added at the end of the
|
||||
* downlink or rx list
|
||||
* @ipc_devlink: Pointer to ipc_devlink data-struct
|
||||
* @skb: Pointer to sk buffer
|
||||
*/
|
||||
void ipc_imem_sys_devlink_notify_rx(struct iosm_devlink *ipc_devlink,
|
||||
struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* ipc_imem_sys_devlink_read - Copy the rx data and free the skbuf
|
||||
* @ipc_devlink: Devlink instance
|
||||
* @data: Buffer to read the data from modem
|
||||
* @bytes_to_read: Size of destination buffer
|
||||
* @bytes_read: Number of bytes read
|
||||
*
|
||||
* Return: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_imem_sys_devlink_read(struct iosm_devlink *ipc_devlink, u8 *data,
|
||||
u32 bytes_to_read, u32 *bytes_read);
|
||||
|
||||
/**
|
||||
* ipc_imem_sys_devlink_write - Route the uplink buffer to CP
|
||||
* @ipc_devlink: Devlink_sio instance
|
||||
* @buf: Pointer to buffer
|
||||
* @count: Number of data bytes to write
|
||||
* Return: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_imem_sys_devlink_write(struct iosm_devlink *ipc_devlink,
|
||||
unsigned char *buf, int count);
|
||||
#endif
|
||||
|
||||
@@ -335,7 +335,6 @@ static int fdp_nci_i2c_probe(struct i2c_client *client)
|
||||
return r;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "I2C driver loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,8 @@ static int microread_mei_probe(struct mei_cl_device *cldev,
|
||||
pr_info("Probing NFC microread\n");
|
||||
|
||||
phy = nfc_mei_phy_alloc(cldev);
|
||||
if (!phy) {
|
||||
pr_err("Cannot allocate memory for microread mei phy.\n");
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
|
||||
MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
|
||||
|
||||
@@ -76,10 +76,8 @@ static struct sk_buff *alloc_lc_skb(struct nfcmrvl_private *priv, uint8_t plen)
|
||||
struct nci_data_hdr *hdr;
|
||||
|
||||
skb = nci_skb_alloc(priv->ndev, (NCI_DATA_HDR_SIZE + plen), GFP_KERNEL);
|
||||
if (!skb) {
|
||||
pr_err("no memory for data\n");
|
||||
if (!skb)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdr = skb_put(skb, NCI_DATA_HDR_SIZE);
|
||||
hdr->conn_id = NCI_CORE_LC_CONNID_PROP_FW_DL;
|
||||
|
||||
@@ -128,7 +128,6 @@ static int pn533_i2c_read(struct pn533_i2c_phy *phy, struct sk_buff **skb)
|
||||
static irqreturn_t pn533_i2c_irq_thread_fn(int irq, void *data)
|
||||
{
|
||||
struct pn533_i2c_phy *phy = data;
|
||||
struct i2c_client *client;
|
||||
struct sk_buff *skb = NULL;
|
||||
int r;
|
||||
|
||||
@@ -137,9 +136,6 @@ static irqreturn_t pn533_i2c_irq_thread_fn(int irq, void *data)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
client = phy->i2c_dev;
|
||||
dev_dbg(&client->dev, "IRQ\n");
|
||||
|
||||
if (phy->hard_fault != 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
|
||||
@@ -1235,8 +1235,6 @@ static void pn533_listen_mode_timer(struct timer_list *t)
|
||||
{
|
||||
struct pn533 *dev = from_timer(dev, t, listen_timer);
|
||||
|
||||
dev_dbg(dev->dev, "Listen mode timeout\n");
|
||||
|
||||
dev->cancel_listen = 1;
|
||||
|
||||
pn533_poll_next_mod(dev);
|
||||
@@ -2173,7 +2171,7 @@ void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status)
|
||||
}
|
||||
|
||||
if (skb == NULL) {
|
||||
pr_err("NULL Frame -> link is dead\n");
|
||||
dev_err(dev->dev, "NULL Frame -> link is dead\n");
|
||||
goto sched_wq;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,9 @@ static int pn544_mei_probe(struct mei_cl_device *cldev,
|
||||
struct nfc_mei_phy *phy;
|
||||
int r;
|
||||
|
||||
pr_info("Probing NFC pn544\n");
|
||||
|
||||
phy = nfc_mei_phy_alloc(cldev);
|
||||
if (!phy) {
|
||||
pr_err("Cannot allocate memory for pn544 mei phy.\n");
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
|
||||
MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
|
||||
@@ -46,8 +42,6 @@ static void pn544_mei_remove(struct mei_cl_device *cldev)
|
||||
{
|
||||
struct nfc_mei_phy *phy = mei_cldev_get_drvdata(cldev);
|
||||
|
||||
pr_info("Removing pn544\n");
|
||||
|
||||
pn544_hci_remove(phy->hdev);
|
||||
|
||||
nfc_mei_phy_free(phy);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* https://github.com/richardcochran/regen
|
||||
*
|
||||
* Hand modified to include some HW registers.
|
||||
* Based on 4.8.0, SCSR rev C commit a03c7ae5
|
||||
* Based on 5.2.0, Family Programming Guide (Sept 30, 2020)
|
||||
*/
|
||||
#ifndef HAVE_IDT8A340_REG
|
||||
#define HAVE_IDT8A340_REG
|
||||
@@ -100,6 +100,7 @@
|
||||
|
||||
#define RESET_CTRL 0xc000
|
||||
#define SM_RESET 0x0012
|
||||
#define SM_RESET_V520 0x0013
|
||||
#define SM_RESET_CMD 0x5A
|
||||
|
||||
#define GENERAL_STATUS 0xc014
|
||||
@@ -130,6 +131,8 @@
|
||||
#define GPIO_USER_CONTROL 0xc160
|
||||
#define GPIO0_TO_7_OUT 0x0000
|
||||
#define GPIO8_TO_15_OUT 0x0001
|
||||
#define GPIO0_TO_7_OUT_V520 0x0002
|
||||
#define GPIO8_TO_15_OUT_V520 0x0003
|
||||
|
||||
#define STICKY_STATUS_CLEAR 0xc164
|
||||
|
||||
@@ -216,22 +219,27 @@
|
||||
#define DPLL_REF_MODE 0x0035
|
||||
#define DPLL_PHASE_MEASUREMENT_CFG 0x0036
|
||||
#define DPLL_MODE 0x0037
|
||||
#define DPLL_MODE_V520 0x003B
|
||||
|
||||
#define DPLL_1 0xc400
|
||||
|
||||
#define DPLL_2 0xc438
|
||||
#define DPLL_2_V520 0xc43c
|
||||
|
||||
#define DPLL_3 0xc480
|
||||
|
||||
#define DPLL_4 0xc4b8
|
||||
#define DPLL_4_V520 0xc4bc
|
||||
|
||||
#define DPLL_5 0xc500
|
||||
|
||||
#define DPLL_6 0xc538
|
||||
#define DPLL_6_V520 0xc53c
|
||||
|
||||
#define DPLL_7 0xc580
|
||||
|
||||
#define SYS_DPLL 0xc5b8
|
||||
#define SYS_DPLL_V520 0xc5bc
|
||||
|
||||
#define DPLL_CTRL_0 0xc600
|
||||
#define DPLL_CTRL_DPLL_MANU_REF_CFG 0x0001
|
||||
@@ -331,6 +339,7 @@
|
||||
#define GPIO_ALERT_OUT_CFG 0x000e
|
||||
#define GPIO_TOD_NOTIFICATION_CFG 0x000f
|
||||
#define GPIO_CTRL 0x0010
|
||||
#define GPIO_CTRL_V520 0x0011
|
||||
|
||||
#define GPIO_1 0xc8d4
|
||||
|
||||
@@ -365,6 +374,7 @@
|
||||
#define OUT_DIV_MUX 0xca12
|
||||
|
||||
#define OUTPUT_0 0xca14
|
||||
#define OUTPUT_0_V520 0xca20
|
||||
/* FOD frequency output divider value */
|
||||
#define OUT_DIV 0x0000
|
||||
#define OUT_DUTY_CYCLE_HIGH 0x0004
|
||||
@@ -374,28 +384,40 @@
|
||||
#define OUT_PHASE_ADJ 0x000c
|
||||
|
||||
#define OUTPUT_1 0xca24
|
||||
#define OUTPUT_1_V520 0xca30
|
||||
|
||||
#define OUTPUT_2 0xca34
|
||||
#define OUTPUT_2_V520 0xca40
|
||||
|
||||
#define OUTPUT_3 0xca44
|
||||
#define OUTPUT_3_V520 0xca50
|
||||
|
||||
#define OUTPUT_4 0xca54
|
||||
#define OUTPUT_4_V520 0xca60
|
||||
|
||||
#define OUTPUT_5 0xca64
|
||||
#define OUTPUT_5_V520 0xca80
|
||||
|
||||
#define OUTPUT_6 0xca80
|
||||
#define OUTPUT_6_V520 0xca90
|
||||
|
||||
#define OUTPUT_7 0xca90
|
||||
#define OUTPUT_7_V520 0xcaa0
|
||||
|
||||
#define OUTPUT_8 0xcaa0
|
||||
#define OUTPUT_8_V520 0xcab0
|
||||
|
||||
#define OUTPUT_9 0xcab0
|
||||
#define OUTPUT_9_V520 0xcac0
|
||||
|
||||
#define OUTPUT_10 0xcac0
|
||||
#define OUTPUT_10_V520 0xcad0
|
||||
|
||||
#define OUTPUT_11 0xcad0
|
||||
#define OUTPUT_11_V520 0xcae0
|
||||
|
||||
#define SERIAL 0xcae0
|
||||
#define SERIAL_V520 0xcaf0
|
||||
|
||||
#define PWM_ENCODER_0 0xcb00
|
||||
|
||||
@@ -416,50 +438,72 @@
|
||||
#define PWM_DECODER_0 0xcb40
|
||||
|
||||
#define PWM_DECODER_1 0xcb48
|
||||
#define PWM_DECODER_1_V520 0xcb4a
|
||||
|
||||
#define PWM_DECODER_2 0xcb50
|
||||
#define PWM_DECODER_2_V520 0xcb54
|
||||
|
||||
#define PWM_DECODER_3 0xcb58
|
||||
#define PWM_DECODER_3_V520 0xcb5e
|
||||
|
||||
#define PWM_DECODER_4 0xcb60
|
||||
#define PWM_DECODER_4_V520 0xcb68
|
||||
|
||||
#define PWM_DECODER_5 0xcb68
|
||||
#define PWM_DECODER_5_V520 0xcb80
|
||||
|
||||
#define PWM_DECODER_6 0xcb70
|
||||
#define PWM_DECODER_6_V520 0xcb8a
|
||||
|
||||
#define PWM_DECODER_7 0xcb80
|
||||
#define PWM_DECODER_7_V520 0xcb94
|
||||
|
||||
#define PWM_DECODER_8 0xcb88
|
||||
#define PWM_DECODER_8_V520 0xcb9e
|
||||
|
||||
#define PWM_DECODER_9 0xcb90
|
||||
#define PWM_DECODER_9_V520 0xcba8
|
||||
|
||||
#define PWM_DECODER_10 0xcb98
|
||||
#define PWM_DECODER_10_V520 0xcbb2
|
||||
|
||||
#define PWM_DECODER_11 0xcba0
|
||||
#define PWM_DECODER_11_V520 0xcbbc
|
||||
|
||||
#define PWM_DECODER_12 0xcba8
|
||||
#define PWM_DECODER_12_V520 0xcbc6
|
||||
|
||||
#define PWM_DECODER_13 0xcbb0
|
||||
#define PWM_DECODER_13_V520 0xcbd0
|
||||
|
||||
#define PWM_DECODER_14 0xcbb8
|
||||
#define PWM_DECODER_14_V520 0xcbda
|
||||
|
||||
#define PWM_DECODER_15 0xcbc0
|
||||
#define PWM_DECODER_15_V520 0xcbe4
|
||||
|
||||
#define PWM_USER_DATA 0xcbc8
|
||||
#define PWM_USER_DATA_V520 0xcbf0
|
||||
|
||||
#define TOD_0 0xcbcc
|
||||
#define TOD_0_V520 0xcc00
|
||||
|
||||
/* Enable TOD counter, output channel sync and even-PPS mode */
|
||||
#define TOD_CFG 0x0000
|
||||
#define TOD_CFG_V520 0x0001
|
||||
|
||||
#define TOD_1 0xcbce
|
||||
#define TOD_1_V520 0xcc02
|
||||
|
||||
#define TOD_2 0xcbd0
|
||||
#define TOD_2_V520 0xcc04
|
||||
|
||||
#define TOD_3 0xcbd2
|
||||
#define TOD_3_V520 0xcc06
|
||||
|
||||
|
||||
#define TOD_WRITE_0 0xcc00
|
||||
#define TOD_WRITE_0_V520 0xcc10
|
||||
/* 8-bit subns, 32-bit ns, 48-bit seconds */
|
||||
#define TOD_WRITE 0x0000
|
||||
/* Counter increments after TOD write is completed */
|
||||
@@ -470,12 +514,16 @@
|
||||
#define TOD_WRITE_CMD 0x000f
|
||||
|
||||
#define TOD_WRITE_1 0xcc10
|
||||
#define TOD_WRITE_1_V520 0xcc20
|
||||
|
||||
#define TOD_WRITE_2 0xcc20
|
||||
#define TOD_WRITE_2_V520 0xcc30
|
||||
|
||||
#define TOD_WRITE_3 0xcc30
|
||||
#define TOD_WRITE_3_V520 0xcc40
|
||||
|
||||
#define TOD_READ_PRIMARY_0 0xcc40
|
||||
#define TOD_READ_PRIMARY_0_V520 0xcc50
|
||||
/* 8-bit subns, 32-bit ns, 48-bit seconds */
|
||||
#define TOD_READ_PRIMARY 0x0000
|
||||
/* Counter increments after TOD write is completed */
|
||||
@@ -484,22 +532,31 @@
|
||||
#define TOD_READ_PRIMARY_SEL_CFG_0 0x000c
|
||||
/* Read trigger selection */
|
||||
#define TOD_READ_PRIMARY_CMD 0x000e
|
||||
#define TOD_READ_PRIMARY_CMD_V520 0x000f
|
||||
|
||||
#define TOD_READ_PRIMARY_1 0xcc50
|
||||
#define TOD_READ_PRIMARY_1_V520 0xcc60
|
||||
|
||||
#define TOD_READ_PRIMARY_2 0xcc60
|
||||
#define TOD_READ_PRIMARY_2_V520 0xcc80
|
||||
|
||||
#define TOD_READ_PRIMARY_3 0xcc80
|
||||
#define TOD_READ_PRIMARY_3_V520 0xcc90
|
||||
|
||||
#define TOD_READ_SECONDARY_0 0xcc90
|
||||
#define TOD_READ_SECONDARY_0_V520 0xcca0
|
||||
|
||||
#define TOD_READ_SECONDARY_1 0xcca0
|
||||
#define TOD_READ_SECONDARY_1_V520 0xccb0
|
||||
|
||||
#define TOD_READ_SECONDARY_2 0xccb0
|
||||
#define TOD_READ_SECONDARY_2_V520 0xccc0
|
||||
|
||||
#define TOD_READ_SECONDARY_3 0xccc0
|
||||
#define TOD_READ_SECONDARY_3_V520 0xccd0
|
||||
|
||||
#define OUTPUT_TDC_CFG 0xccd0
|
||||
#define OUTPUT_TDC_CFG_V520 0xcce0
|
||||
|
||||
#define OUTPUT_TDC_0 0xcd00
|
||||
|
||||
@@ -512,8 +569,10 @@
|
||||
#define INPUT_TDC 0xcd20
|
||||
|
||||
#define SCRATCH 0xcf50
|
||||
#define SCRATCH_V520 0xcf4c
|
||||
|
||||
#define EEPROM 0xcf68
|
||||
#define EEPROM_V520 0xcf64
|
||||
|
||||
#define OTP 0xcf70
|
||||
|
||||
@@ -576,6 +635,10 @@
|
||||
#define STATE_MODE_SHIFT (0)
|
||||
#define STATE_MODE_MASK (0x7)
|
||||
|
||||
/* Bit definitions for the DPLL_MANU_REF_CFG register */
|
||||
#define MANUAL_REFERENCE_SHIFT (0)
|
||||
#define MANUAL_REFERENCE_MASK (0x1f)
|
||||
|
||||
/* Bit definitions for the GPIO_CFG_GBL register */
|
||||
#define SUPPLY_MODE_SHIFT (0)
|
||||
#define SUPPLY_MODE_MASK (0x3)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,15 +57,27 @@
|
||||
|
||||
#define IDTCM_MAX_WRITE_COUNT (512)
|
||||
|
||||
#define FULL_FW_CFG_BYTES (SCRATCH - GPIO_USER_CONTROL)
|
||||
#define FULL_FW_CFG_SKIPPED_BYTES (((SCRATCH >> 7) \
|
||||
- (GPIO_USER_CONTROL >> 7)) \
|
||||
* 4) /* 4 bytes skipped every 0x80 */
|
||||
#define PHASE_PULL_IN_MAX_PPB (144000)
|
||||
#define PHASE_PULL_IN_MIN_THRESHOLD_NS (2)
|
||||
|
||||
/*
|
||||
* Return register address based on passed in firmware version
|
||||
*/
|
||||
#define IDTCM_FW_REG(FW, VER, REG) (((FW) < (VER)) ? (REG) : (REG##_##VER))
|
||||
|
||||
/* PTP PLL Mode */
|
||||
enum ptp_pll_mode {
|
||||
PTP_PLL_MODE_MIN = 0,
|
||||
PTP_PLL_MODE_WRITE_FREQUENCY = PTP_PLL_MODE_MIN,
|
||||
PTP_PLL_MODE_WRITE_PHASE,
|
||||
PTP_PLL_MODE_UNSUPPORTED,
|
||||
PTP_PLL_MODE_MAX = PTP_PLL_MODE_UNSUPPORTED,
|
||||
};
|
||||
|
||||
/* Values of DPLL_N.DPLL_MODE.PLL_MODE */
|
||||
enum pll_mode {
|
||||
PLL_MODE_MIN = 0,
|
||||
PLL_MODE_NORMAL = PLL_MODE_MIN,
|
||||
PLL_MODE_PLL = PLL_MODE_MIN,
|
||||
PLL_MODE_WRITE_PHASE = 1,
|
||||
PLL_MODE_WRITE_FREQUENCY = 2,
|
||||
PLL_MODE_GPIO_INC_DEC = 3,
|
||||
@@ -75,6 +87,31 @@ enum pll_mode {
|
||||
PLL_MODE_MAX = PLL_MODE_DISABLED,
|
||||
};
|
||||
|
||||
/* Values of DPLL_CTRL_n.DPLL_MANU_REF_CFG.MANUAL_REFERENCE */
|
||||
enum manual_reference {
|
||||
MANU_REF_MIN = 0,
|
||||
MANU_REF_CLK0 = MANU_REF_MIN,
|
||||
MANU_REF_CLK1,
|
||||
MANU_REF_CLK2,
|
||||
MANU_REF_CLK3,
|
||||
MANU_REF_CLK4,
|
||||
MANU_REF_CLK5,
|
||||
MANU_REF_CLK6,
|
||||
MANU_REF_CLK7,
|
||||
MANU_REF_CLK8,
|
||||
MANU_REF_CLK9,
|
||||
MANU_REF_CLK10,
|
||||
MANU_REF_CLK11,
|
||||
MANU_REF_CLK12,
|
||||
MANU_REF_CLK13,
|
||||
MANU_REF_CLK14,
|
||||
MANU_REF_CLK15,
|
||||
MANU_REF_WRITE_PHASE,
|
||||
MANU_REF_WRITE_FREQUENCY,
|
||||
MANU_REF_XO_DPLL,
|
||||
MANU_REF_MAX = MANU_REF_XO_DPLL,
|
||||
};
|
||||
|
||||
enum hw_tod_write_trig_sel {
|
||||
HW_TOD_WR_TRIG_SEL_MIN = 0,
|
||||
HW_TOD_WR_TRIG_SEL_MSB = HW_TOD_WR_TRIG_SEL_MIN,
|
||||
@@ -119,6 +156,12 @@ enum dpll_state {
|
||||
DPLL_STATE_MAX = DPLL_STATE_OPEN_LOOP,
|
||||
};
|
||||
|
||||
enum fw_version {
|
||||
V_DEFAULT = 0,
|
||||
V487 = 1,
|
||||
V520 = 2,
|
||||
};
|
||||
|
||||
struct idtcm;
|
||||
|
||||
struct idtcm_channel {
|
||||
@@ -134,7 +177,14 @@ struct idtcm_channel {
|
||||
u16 tod_write;
|
||||
u16 tod_n;
|
||||
u16 hw_dpll_n;
|
||||
enum pll_mode pll_mode;
|
||||
u8 sync_src;
|
||||
enum ptp_pll_mode mode;
|
||||
int (*configure_write_frequency)(struct idtcm_channel *channel);
|
||||
int (*configure_write_phase)(struct idtcm_channel *channel);
|
||||
int (*do_phase_pull_in)(struct idtcm_channel *channel,
|
||||
s32 offset_ns, u32 max_ffo_ppb);
|
||||
s32 current_freq_scaled_ppm;
|
||||
bool phase_pull_in;
|
||||
u8 pll;
|
||||
u16 output_mask;
|
||||
};
|
||||
@@ -145,7 +195,7 @@ struct idtcm {
|
||||
u8 page_offset;
|
||||
u8 tod_mask;
|
||||
char version[16];
|
||||
u8 deprecated;
|
||||
enum fw_version fw_ver;
|
||||
|
||||
/* Overhead calculation for adjtime */
|
||||
u8 calculate_overhead_flag;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -182,7 +182,7 @@ static void ctcmpc_chx_attnbusy(fsm_instance *, int, void *);
|
||||
static void ctcmpc_chx_resend(fsm_instance *, int, void *);
|
||||
static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Check return code of a preceding ccw_device call, halt_IO etc...
|
||||
*
|
||||
* ch : The channel, the error belongs to.
|
||||
@@ -223,7 +223,7 @@ void ctcm_purge_skb_queue(struct sk_buff_head *q)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* NOP action for statemachines
|
||||
*/
|
||||
static void ctcm_action_nop(fsm_instance *fi, int event, void *arg)
|
||||
@@ -234,7 +234,7 @@ static void ctcm_action_nop(fsm_instance *fi, int event, void *arg)
|
||||
* Actions for channel - statemachines.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* Normal data has been send. Free the corresponding
|
||||
* skb (it's in io_queue), reset dev->tbusy and
|
||||
* revert to idle state.
|
||||
@@ -322,7 +322,7 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg)
|
||||
ctcm_clear_busy_do(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initial data is sent.
|
||||
* Notify device statemachine that we are up and
|
||||
* running.
|
||||
@@ -344,7 +344,7 @@ void ctcm_chx_txidle(fsm_instance *fi, int event, void *arg)
|
||||
fsm_event(priv->fsm, DEV_EVENT_TXUP, ch->netdev);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Got normal data, check for sanity, queue it up, allocate new buffer
|
||||
* trigger bottom half, and initiate next read.
|
||||
*
|
||||
@@ -421,7 +421,7 @@ static void chx_rx(fsm_instance *fi, int event, void *arg)
|
||||
ctcm_ccw_check_rc(ch, rc, "normal RX");
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initialize connection by sending a __u16 of value 0.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -497,7 +497,7 @@ static void chx_firstio(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Got initial data, check it. If OK,
|
||||
* notify device statemachine that we are up and
|
||||
* running.
|
||||
@@ -538,7 +538,7 @@ static void chx_rxidle(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Set channel into extended mode.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -578,7 +578,7 @@ static void ctcm_chx_setmode(fsm_instance *fi, int event, void *arg)
|
||||
ch->retry = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Setup channel.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -641,7 +641,7 @@ static void ctcm_chx_start(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Shutdown a channel.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -682,7 +682,7 @@ static void ctcm_chx_haltio(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Cleanup helper for chx_fail and chx_stopped
|
||||
* cleanup channels queue and notify interface statemachine.
|
||||
*
|
||||
@@ -728,7 +728,7 @@ static void ctcm_chx_cleanup(fsm_instance *fi, int state,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* A channel has successfully been halted.
|
||||
* Cleanup it's queue and notify interface statemachine.
|
||||
*
|
||||
@@ -741,7 +741,7 @@ static void ctcm_chx_stopped(fsm_instance *fi, int event, void *arg)
|
||||
ctcm_chx_cleanup(fi, CTC_STATE_STOPPED, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* A stop command from device statemachine arrived and we are in
|
||||
* not operational mode. Set state to stopped.
|
||||
*
|
||||
@@ -754,7 +754,7 @@ static void ctcm_chx_stop(fsm_instance *fi, int event, void *arg)
|
||||
fsm_newstate(fi, CTC_STATE_STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* A machine check for no path, not operational status or gone device has
|
||||
* happened.
|
||||
* Cleanup queue and notify interface statemachine.
|
||||
@@ -768,7 +768,7 @@ static void ctcm_chx_fail(fsm_instance *fi, int event, void *arg)
|
||||
ctcm_chx_cleanup(fi, CTC_STATE_NOTOP, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Handle error during setup of channel.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -817,7 +817,7 @@ static void ctcm_chx_setuperr(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Restart a channel after an error.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -858,7 +858,7 @@ static void ctcm_chx_restart(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Handle error during RX initial handshake (exchange of
|
||||
* 0-length block header)
|
||||
*
|
||||
@@ -893,7 +893,7 @@ static void ctcm_chx_rxiniterr(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Notify device statemachine if we gave up initialization
|
||||
* of RX channel.
|
||||
*
|
||||
@@ -914,7 +914,7 @@ static void ctcm_chx_rxinitfail(fsm_instance *fi, int event, void *arg)
|
||||
fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Handle RX Unit check remote reset (remote disconnected)
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -946,7 +946,7 @@ static void ctcm_chx_rxdisc(fsm_instance *fi, int event, void *arg)
|
||||
ccw_device_halt(ch2->cdev, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Handle error during TX channel initialization.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -978,7 +978,7 @@ static void ctcm_chx_txiniterr(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Handle TX timeout by retrying operation.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -1050,7 +1050,7 @@ done:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Handle fatal errors during an I/O command.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -1198,7 +1198,7 @@ int ch_fsm_len = ARRAY_SIZE(ch_fsm);
|
||||
* Actions for mpc channel statemachine.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* Normal data has been send. Free the corresponding
|
||||
* skb (it's in io_queue), reset dev->tbusy and
|
||||
* revert to idle state.
|
||||
@@ -1361,7 +1361,7 @@ done:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Got normal data, check for sanity, queue it up, allocate new buffer
|
||||
* trigger bottom half, and initiate next read.
|
||||
*
|
||||
@@ -1464,7 +1464,7 @@ again:
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initialize connection by sending a __u16 of value 0.
|
||||
*
|
||||
* fi An instance of a channel statemachine.
|
||||
@@ -1516,7 +1516,7 @@ done:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Got initial data, check it. If OK,
|
||||
* notify device statemachine that we are up and
|
||||
* running.
|
||||
@@ -2043,7 +2043,7 @@ int mpc_ch_fsm_len = ARRAY_SIZE(ctcmpc_ch_fsm);
|
||||
* Actions for interface - statemachine.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* Startup channels by sending CTC_EVENT_START to each channel.
|
||||
*
|
||||
* fi An instance of an interface statemachine.
|
||||
@@ -2068,7 +2068,7 @@ static void dev_action_start(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Shutdown channels by sending CTC_EVENT_STOP to each channel.
|
||||
*
|
||||
* fi An instance of an interface statemachine.
|
||||
@@ -2122,7 +2122,7 @@ static void dev_action_restart(fsm_instance *fi, int event, void *arg)
|
||||
DEV_EVENT_START, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Called from channel statemachine
|
||||
* when a channel is up and running.
|
||||
*
|
||||
@@ -2183,7 +2183,7 @@ static void dev_action_chup(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Called from device statemachine
|
||||
* when a channel has been shutdown.
|
||||
*
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
/* Some common global variables */
|
||||
|
||||
/**
|
||||
/*
|
||||
* The root device for ctcm group devices
|
||||
*/
|
||||
static struct device *ctcm_root_dev;
|
||||
@@ -65,7 +65,7 @@ static struct device *ctcm_root_dev;
|
||||
*/
|
||||
struct channel *channels;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Unpack a just received skb and hand it over to
|
||||
* upper layers.
|
||||
*
|
||||
@@ -180,7 +180,7 @@ void ctcm_unpack_skb(struct channel *ch, struct sk_buff *pskb)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Release a specific channel in the channel list.
|
||||
*
|
||||
* ch Pointer to channel struct to be released.
|
||||
@@ -192,7 +192,7 @@ static void channel_free(struct channel *ch)
|
||||
fsm_newstate(ch->fsm, CTC_STATE_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Remove a specific channel in the channel list.
|
||||
*
|
||||
* ch Pointer to channel struct to be released.
|
||||
@@ -240,7 +240,7 @@ static void channel_remove(struct channel *ch)
|
||||
chid, ok ? "OK" : "failed");
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Get a specific channel from the channel list.
|
||||
*
|
||||
* type Type of channel we are interested in.
|
||||
@@ -300,7 +300,7 @@ static long ctcm_check_irb_error(struct ccw_device *cdev, struct irb *irb)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Check sense of a unit check.
|
||||
*
|
||||
* ch The channel, the sense code belongs to.
|
||||
@@ -414,7 +414,7 @@ int ctcm_ch_alloc_buffer(struct channel *ch)
|
||||
* Interface API for upper network layers
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* Open an interface.
|
||||
* Called from generic network layer when ifconfig up is run.
|
||||
*
|
||||
@@ -432,7 +432,7 @@ int ctcm_open(struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Close an interface.
|
||||
* Called from generic network layer when ifconfig down is run.
|
||||
*
|
||||
@@ -451,7 +451,7 @@ int ctcm_close(struct net_device *dev)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Transmit a packet.
|
||||
* This is a helper function for ctcm_tx().
|
||||
*
|
||||
@@ -822,7 +822,7 @@ done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Start transmission of a packet.
|
||||
* Called from generic network device layer.
|
||||
*
|
||||
@@ -975,7 +975,7 @@ done:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Sets MTU of an interface.
|
||||
*
|
||||
* dev Pointer to interface struct.
|
||||
@@ -1007,7 +1007,7 @@ static int ctcm_change_mtu(struct net_device *dev, int new_mtu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Returns interface statistics of a device.
|
||||
*
|
||||
* dev Pointer to interface struct.
|
||||
@@ -1144,7 +1144,7 @@ static struct net_device *ctcm_init_netdevice(struct ctcm_priv *priv)
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Main IRQ handler.
|
||||
*
|
||||
* cdev The ccw_device the interrupt is for.
|
||||
@@ -1257,7 +1257,7 @@ static const struct device_type ctcm_devtype = {
|
||||
.groups = ctcm_attr_groups,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Add ctcm specific attributes.
|
||||
* Add ctcm private data.
|
||||
*
|
||||
@@ -1293,7 +1293,7 @@ static int ctcm_probe_device(struct ccwgroup_device *cgdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Add a new channel to the list of channels.
|
||||
* Keeps the channel list sorted.
|
||||
*
|
||||
@@ -1343,7 +1343,7 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type,
|
||||
snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev->dev));
|
||||
ch->type = type;
|
||||
|
||||
/**
|
||||
/*
|
||||
* "static" ccws are used in the following way:
|
||||
*
|
||||
* ccw[0..2] (Channel program for generic I/O):
|
||||
@@ -1471,7 +1471,7 @@ static enum ctcm_channel_types get_channel_type(struct ccw_device_id *id)
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
*
|
||||
* Setup an interface.
|
||||
*
|
||||
@@ -1595,7 +1595,7 @@ out_err_result:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Shutdown an interface.
|
||||
*
|
||||
* cgdev Device to be shut down.
|
||||
@@ -1738,7 +1738,7 @@ static void print_banner(void)
|
||||
pr_info("CTCM driver initialized\n");
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initialize module.
|
||||
* This is called just after the module is loaded.
|
||||
*
|
||||
|
||||
@@ -1016,7 +1016,7 @@ done:
|
||||
CTCM_PR_DEBUG("exit %s: ch=0x%p id=%s\n", __func__, ch, ch->id);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Unpack a just received skb and hand it over to
|
||||
* upper layers.
|
||||
* special MPC version of unpack_skb.
|
||||
@@ -1211,7 +1211,7 @@ done:
|
||||
__func__, dev->name, ch, ch->id);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* tasklet helper for mpc's skb unpacking.
|
||||
*
|
||||
* ch The channel to work on.
|
||||
@@ -1320,7 +1320,7 @@ struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv)
|
||||
* CTCM_PROTO_MPC only
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* NOP action for statemachines
|
||||
*/
|
||||
static void mpc_action_nop(fsm_instance *fi, int event, void *arg)
|
||||
@@ -1426,7 +1426,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Handle mpc group action timeout.
|
||||
* MPC Group Station FSM action
|
||||
* CTCM_PROTO_MPC only
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
/*
|
||||
* A generic FSM based on fsm used in isdn4linux
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -555,7 +555,7 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
if (ret)
|
||||
goto err_disable;
|
||||
|
||||
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
|
||||
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
|
||||
if (ret)
|
||||
goto err_resource;
|
||||
|
||||
|
||||
@@ -40,18 +40,18 @@
|
||||
#error Cannot compile lcs.c without some net devices switched on.
|
||||
#endif
|
||||
|
||||
/**
|
||||
/*
|
||||
* initialization string for output
|
||||
*/
|
||||
|
||||
static char version[] __initdata = "LCS driver";
|
||||
|
||||
/**
|
||||
/*
|
||||
* the root device for lcs group devices
|
||||
*/
|
||||
static struct device *lcs_root_dev;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Some prototypes.
|
||||
*/
|
||||
static void lcs_tasklet(unsigned long);
|
||||
@@ -62,14 +62,14 @@ static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *);
|
||||
#endif /* CONFIG_IP_MULTICAST */
|
||||
static int lcs_recovery(void *ptr);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Debug Facility Stuff
|
||||
*/
|
||||
static char debug_buffer[255];
|
||||
static debug_info_t *lcs_dbf_setup;
|
||||
static debug_info_t *lcs_dbf_trace;
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS Debug Facility functions
|
||||
*/
|
||||
static void
|
||||
@@ -96,7 +96,7 @@ lcs_register_debug_facility(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Allocate io buffers.
|
||||
*/
|
||||
static int
|
||||
@@ -123,7 +123,7 @@ lcs_alloc_channel(struct lcs_channel *channel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Free io buffers.
|
||||
*/
|
||||
static void
|
||||
@@ -151,7 +151,7 @@ lcs_cleanup_channel(struct lcs_channel *channel)
|
||||
lcs_free_channel(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS free memory for card and channels.
|
||||
*/
|
||||
static void
|
||||
@@ -162,7 +162,7 @@ lcs_free_card(struct lcs_card *card)
|
||||
kfree(card);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS alloc memory for card and channels
|
||||
*/
|
||||
static struct lcs_card *
|
||||
@@ -402,7 +402,7 @@ lcs_do_start_thread(struct lcs_card *card, unsigned long thread)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initialize channels,card and state machines.
|
||||
*/
|
||||
static void
|
||||
@@ -451,7 +451,8 @@ static void lcs_clear_multicast_list(struct lcs_card *card)
|
||||
spin_unlock_irqrestore(&card->ipm_lock, flags);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
|
||||
/*
|
||||
* Cleanup channels,card and state machines.
|
||||
*/
|
||||
static void
|
||||
@@ -468,7 +469,7 @@ lcs_cleanup_card(struct lcs_card *card)
|
||||
lcs_cleanup_channel(&card->read);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Start channel.
|
||||
*/
|
||||
static int
|
||||
@@ -517,7 +518,7 @@ lcs_clear_channel(struct lcs_channel *channel)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Stop channel.
|
||||
*/
|
||||
static int
|
||||
@@ -545,7 +546,7 @@ lcs_stop_channel(struct lcs_channel *channel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* start read and write channel
|
||||
*/
|
||||
static int
|
||||
@@ -565,7 +566,7 @@ lcs_start_channels(struct lcs_card *card)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* stop read and write channel
|
||||
*/
|
||||
static int
|
||||
@@ -577,7 +578,7 @@ lcs_stop_channels(struct lcs_card *card)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Get empty buffer.
|
||||
*/
|
||||
static struct lcs_buffer *
|
||||
@@ -610,7 +611,7 @@ lcs_get_buffer(struct lcs_channel *channel)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Resume channel program if the channel is suspended.
|
||||
*/
|
||||
static int
|
||||
@@ -636,7 +637,7 @@ __lcs_resume_channel(struct lcs_channel *channel)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Make a buffer ready for processing.
|
||||
*/
|
||||
static void __lcs_ready_buffer_bits(struct lcs_channel *channel, int index)
|
||||
@@ -678,7 +679,7 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Mark the buffer as processed. Take care of the suspend bit
|
||||
* of the previous buffer. This function is called from
|
||||
* interrupt context, so the lock must not be taken.
|
||||
@@ -712,7 +713,7 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
return __lcs_resume_channel(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Put a processed buffer back to state empty.
|
||||
*/
|
||||
static void
|
||||
@@ -728,7 +729,7 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Get buffer for a lan command.
|
||||
*/
|
||||
static struct lcs_buffer *
|
||||
@@ -785,7 +786,7 @@ lcs_alloc_reply(struct lcs_cmd *cmd)
|
||||
return reply;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Notifier function for lancmd replies. Called from read irq.
|
||||
*/
|
||||
static void
|
||||
@@ -813,7 +814,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd)
|
||||
spin_unlock(&card->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Emit buffer of a lan command.
|
||||
*/
|
||||
static void
|
||||
@@ -877,7 +878,7 @@ lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer,
|
||||
return rc ? -EIO : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS startup command
|
||||
*/
|
||||
static int
|
||||
@@ -895,7 +896,7 @@ lcs_send_startup(struct lcs_card *card, __u8 initiator)
|
||||
return lcs_send_lancmd(card, buffer, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS shutdown command
|
||||
*/
|
||||
static int
|
||||
@@ -912,7 +913,7 @@ lcs_send_shutdown(struct lcs_card *card)
|
||||
return lcs_send_lancmd(card, buffer, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS lanstat command
|
||||
*/
|
||||
static void
|
||||
@@ -939,7 +940,7 @@ lcs_send_lanstat(struct lcs_card *card)
|
||||
return lcs_send_lancmd(card, buffer, __lcs_lanstat_cb);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* send stoplan command
|
||||
*/
|
||||
static int
|
||||
@@ -958,7 +959,7 @@ lcs_send_stoplan(struct lcs_card *card, __u8 initiator)
|
||||
return lcs_send_lancmd(card, buffer, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* send startlan command
|
||||
*/
|
||||
static void
|
||||
@@ -986,7 +987,7 @@ lcs_send_startlan(struct lcs_card *card, __u8 initiator)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IP_MULTICAST
|
||||
/**
|
||||
/*
|
||||
* send setipm command (Multicast)
|
||||
*/
|
||||
static int
|
||||
@@ -1010,7 +1011,7 @@ lcs_send_setipm(struct lcs_card *card,struct lcs_ipm_list *ipm_list)
|
||||
return lcs_send_lancmd(card, buffer, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* send delipm command (Multicast)
|
||||
*/
|
||||
static int
|
||||
@@ -1034,7 +1035,7 @@ lcs_send_delipm(struct lcs_card *card,struct lcs_ipm_list *ipm_list)
|
||||
return lcs_send_lancmd(card, buffer, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* check if multicast is supported by LCS
|
||||
*/
|
||||
static void
|
||||
@@ -1074,7 +1075,7 @@ lcs_check_multicast_support(struct lcs_card *card)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* set or del multicast address on LCS card
|
||||
*/
|
||||
static void
|
||||
@@ -1129,7 +1130,7 @@ list_modified:
|
||||
spin_unlock_irqrestore(&card->ipm_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* get mac address for the relevant Multicast address
|
||||
*/
|
||||
static void
|
||||
@@ -1139,7 +1140,7 @@ lcs_get_mac_for_ipm(__be32 ipm, char *mac, struct net_device *dev)
|
||||
ip_eth_mc_map(ipm, mac);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* function called by net device to handle multicast address relevant things
|
||||
*/
|
||||
static void lcs_remove_mc_addresses(struct lcs_card *card,
|
||||
@@ -1260,7 +1261,7 @@ out:
|
||||
}
|
||||
#endif /* CONFIG_IP_MULTICAST */
|
||||
|
||||
/**
|
||||
/*
|
||||
* function called by net device to
|
||||
* handle multicast address relevant things
|
||||
*/
|
||||
@@ -1355,7 +1356,7 @@ lcs_schedule_recovery(struct lcs_card *card)
|
||||
schedule_work(&card->kernel_thread_starter);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* IRQ Handler for LCS channels
|
||||
*/
|
||||
static void
|
||||
@@ -1439,7 +1440,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
||||
tasklet_schedule(&channel->irq_tasklet);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Tasklet for IRQ handler
|
||||
*/
|
||||
static void
|
||||
@@ -1476,7 +1477,7 @@ lcs_tasklet(unsigned long data)
|
||||
wake_up(&channel->wait_q);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Finish current tx buffer and make it ready for transmit.
|
||||
*/
|
||||
static void
|
||||
@@ -1490,7 +1491,7 @@ __lcs_emit_txbuffer(struct lcs_card *card)
|
||||
card->tx_emitted++;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Callback for finished tx buffers.
|
||||
*/
|
||||
static void
|
||||
@@ -1515,7 +1516,7 @@ lcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
spin_unlock(&card->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Packet transmit function called by network stack
|
||||
*/
|
||||
static int
|
||||
@@ -1593,7 +1594,7 @@ lcs_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* send startlan and lanstat command to make LCS device ready
|
||||
*/
|
||||
static int
|
||||
@@ -1648,7 +1649,7 @@ lcs_startlan(struct lcs_card *card)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS detect function
|
||||
* setup channels and make them I/O ready
|
||||
*/
|
||||
@@ -1680,7 +1681,7 @@ lcs_detect(struct lcs_card *card)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS Stop card
|
||||
*/
|
||||
static int
|
||||
@@ -1705,7 +1706,7 @@ lcs_stopcard(struct lcs_card *card)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Kernel Thread helper functions for LGW initiated commands
|
||||
*/
|
||||
static void
|
||||
@@ -1721,7 +1722,7 @@ lcs_start_kernel_thread(struct work_struct *work)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Process control frames.
|
||||
*/
|
||||
static void
|
||||
@@ -1748,7 +1749,7 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd)
|
||||
lcs_notify_lancmd_waiters(card, cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Unpack network packet.
|
||||
*/
|
||||
static void
|
||||
@@ -1779,7 +1780,7 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len)
|
||||
netif_rx(skb);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS main routine to get packets and lancmd replies from the buffers
|
||||
*/
|
||||
static void
|
||||
@@ -1829,7 +1830,7 @@ lcs_get_frames_cb(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
lcs_ready_buffer(&card->read, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* get network statistics for ifconfig and other user programs
|
||||
*/
|
||||
static struct net_device_stats *
|
||||
@@ -1842,7 +1843,7 @@ lcs_getstats(struct net_device *dev)
|
||||
return &card->stats;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* stop lcs device
|
||||
* This function will be called by user doing ifconfig xxx down
|
||||
*/
|
||||
@@ -1866,7 +1867,7 @@ lcs_stop_device(struct net_device *dev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* start lcs device and make it runnable
|
||||
* This function will be called by user doing ifconfig xxx up
|
||||
*/
|
||||
@@ -1892,7 +1893,7 @@ lcs_open_device(struct net_device *dev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* show function for portno called by cat or similar things
|
||||
*/
|
||||
static ssize_t
|
||||
@@ -1908,7 +1909,7 @@ lcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%d\n", card->portno);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* store the value which is piped to file portno
|
||||
*/
|
||||
static ssize_t
|
||||
@@ -2033,7 +2034,7 @@ static const struct device_type lcs_devtype = {
|
||||
.groups = lcs_attr_groups,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* lcs_probe_device is called on establishing a new ccwgroup_device.
|
||||
*/
|
||||
static int
|
||||
@@ -2077,7 +2078,7 @@ lcs_register_netdev(struct ccwgroup_device *ccwgdev)
|
||||
return register_netdev(card->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* lcs_new_device will be called by setting the group device online.
|
||||
*/
|
||||
static const struct net_device_ops lcs_netdev_ops = {
|
||||
@@ -2199,7 +2200,7 @@ out_err:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* lcs_shutdown_device, called when setting the group device offline.
|
||||
*/
|
||||
static int
|
||||
@@ -2240,7 +2241,7 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
|
||||
return __lcs_shutdown_device(ccwgdev, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* drive lcs recovery after startup and startlan initiated by Lan Gateway
|
||||
*/
|
||||
static int
|
||||
@@ -2271,7 +2272,7 @@ lcs_recovery(void *ptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* lcs_remove_device, free buffers and card
|
||||
*/
|
||||
static void
|
||||
@@ -2315,7 +2316,7 @@ static struct ccw_driver lcs_ccw_driver = {
|
||||
.int_class = IRQIO_LCS,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS ccwgroup driver registration
|
||||
*/
|
||||
static struct ccwgroup_driver lcs_group_driver = {
|
||||
@@ -2351,7 +2352,7 @@ static const struct attribute_group *lcs_drv_attr_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS Module/Kernel initialization function
|
||||
*/
|
||||
static int
|
||||
@@ -2389,7 +2390,7 @@ out_err:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* LCS module cleanup function
|
||||
*/
|
||||
static void
|
||||
|
||||
@@ -58,7 +58,7 @@ MODULE_AUTHOR
|
||||
("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
|
||||
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
|
||||
|
||||
/**
|
||||
/*
|
||||
* Debug Facility stuff
|
||||
*/
|
||||
#define IUCV_DBF_SETUP_NAME "iucv_setup"
|
||||
@@ -107,7 +107,7 @@ DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
|
||||
debug_sprintf_event(iucv_dbf_trace, level, text ); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
/*
|
||||
* some more debug stuff
|
||||
*/
|
||||
#define PRINTK_HEADER " iucv: " /* for debugging */
|
||||
@@ -118,7 +118,7 @@ static struct device_driver netiucv_driver = {
|
||||
.bus = &iucv_bus,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Per connection profiling data
|
||||
*/
|
||||
struct connection_profile {
|
||||
@@ -133,7 +133,7 @@ struct connection_profile {
|
||||
unsigned long tx_max_pending;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Representation of one iucv connection
|
||||
*/
|
||||
struct iucv_connection {
|
||||
@@ -154,13 +154,13 @@ struct iucv_connection {
|
||||
char userdata[17];
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Linked list of all connection structs.
|
||||
*/
|
||||
static LIST_HEAD(iucv_connection_list);
|
||||
static DEFINE_RWLOCK(iucv_connection_rwlock);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Representation of event-data for the
|
||||
* connection state machine.
|
||||
*/
|
||||
@@ -169,7 +169,7 @@ struct iucv_event {
|
||||
void *data;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Private part of the network device structure
|
||||
*/
|
||||
struct netiucv_priv {
|
||||
@@ -180,7 +180,7 @@ struct netiucv_priv {
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Link level header for a packet.
|
||||
*/
|
||||
struct ll_header {
|
||||
@@ -195,7 +195,7 @@ struct ll_header {
|
||||
#define NETIUCV_QUEUELEN_DEFAULT 50
|
||||
#define NETIUCV_TIMEOUT_5SEC 5000
|
||||
|
||||
/**
|
||||
/*
|
||||
* Compatibility macros for busy handling
|
||||
* of network devices.
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ static u8 iucvMagic_ebcdic[16] = {
|
||||
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Convert an iucv userId to its printable
|
||||
* form (strip whitespace at end).
|
||||
*
|
||||
@@ -262,7 +262,7 @@ static char *netiucv_printuser(struct iucv_connection *conn)
|
||||
return netiucv_printname(conn->userid, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* States of the interface statemachine.
|
||||
*/
|
||||
enum dev_states {
|
||||
@@ -270,7 +270,7 @@ enum dev_states {
|
||||
DEV_STATE_STARTWAIT,
|
||||
DEV_STATE_STOPWAIT,
|
||||
DEV_STATE_RUNNING,
|
||||
/**
|
||||
/*
|
||||
* MUST be always the last element!!
|
||||
*/
|
||||
NR_DEV_STATES
|
||||
@@ -283,7 +283,7 @@ static const char *dev_state_names[] = {
|
||||
"Running",
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Events of the interface statemachine.
|
||||
*/
|
||||
enum dev_events {
|
||||
@@ -291,7 +291,7 @@ enum dev_events {
|
||||
DEV_EVENT_STOP,
|
||||
DEV_EVENT_CONUP,
|
||||
DEV_EVENT_CONDOWN,
|
||||
/**
|
||||
/*
|
||||
* MUST be always the last element!!
|
||||
*/
|
||||
NR_DEV_EVENTS
|
||||
@@ -304,11 +304,11 @@ static const char *dev_event_names[] = {
|
||||
"Connection down",
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Events of the connection statemachine
|
||||
*/
|
||||
enum conn_events {
|
||||
/**
|
||||
/*
|
||||
* Events, representing callbacks from
|
||||
* lowlevel iucv layer)
|
||||
*/
|
||||
@@ -320,23 +320,23 @@ enum conn_events {
|
||||
CONN_EVENT_RX,
|
||||
CONN_EVENT_TXDONE,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Events, representing errors return codes from
|
||||
* calls to lowlevel iucv layer
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* Event, representing timer expiry.
|
||||
*/
|
||||
CONN_EVENT_TIMER,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Events, representing commands from upper levels.
|
||||
*/
|
||||
CONN_EVENT_START,
|
||||
CONN_EVENT_STOP,
|
||||
|
||||
/**
|
||||
/*
|
||||
* MUST be always the last element!!
|
||||
*/
|
||||
NR_CONN_EVENTS,
|
||||
@@ -357,55 +357,55 @@ static const char *conn_event_names[] = {
|
||||
"Stop",
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* States of the connection statemachine.
|
||||
*/
|
||||
enum conn_states {
|
||||
/**
|
||||
/*
|
||||
* Connection not assigned to any device,
|
||||
* initial state, invalid
|
||||
*/
|
||||
CONN_STATE_INVALID,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Userid assigned but not operating
|
||||
*/
|
||||
CONN_STATE_STOPPED,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Connection registered,
|
||||
* no connection request sent yet,
|
||||
* no connection request received
|
||||
*/
|
||||
CONN_STATE_STARTWAIT,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Connection registered and connection request sent,
|
||||
* no acknowledge and no connection request received yet.
|
||||
*/
|
||||
CONN_STATE_SETUPWAIT,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Connection up and running idle
|
||||
*/
|
||||
CONN_STATE_IDLE,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Data sent, awaiting CONN_EVENT_TXDONE
|
||||
*/
|
||||
CONN_STATE_TX,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Error during registration.
|
||||
*/
|
||||
CONN_STATE_REGERR,
|
||||
|
||||
/**
|
||||
/*
|
||||
* Error during registration.
|
||||
*/
|
||||
CONN_STATE_CONNERR,
|
||||
|
||||
/**
|
||||
/*
|
||||
* MUST be always the last element!!
|
||||
*/
|
||||
NR_CONN_STATES,
|
||||
@@ -424,7 +424,7 @@ static const char *conn_state_names[] = {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Debug Facility Stuff
|
||||
*/
|
||||
static debug_info_t *iucv_dbf_setup = NULL;
|
||||
@@ -556,7 +556,7 @@ static void netiucv_callback_connres(struct iucv_path *path, u8 *ipuser)
|
||||
fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* NOP action for statemachines
|
||||
*/
|
||||
static void netiucv_action_nop(fsm_instance *fi, int event, void *arg)
|
||||
@@ -567,7 +567,7 @@ static void netiucv_action_nop(fsm_instance *fi, int event, void *arg)
|
||||
* Actions of the connection statemachine
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* netiucv_unpack_skb
|
||||
* @conn: The connection where this skb has been received.
|
||||
* @pskb: The received skb.
|
||||
@@ -993,7 +993,7 @@ static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
|
||||
* Actions for interface - statemachine.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* dev_action_start
|
||||
* @fi: An instance of an interface statemachine.
|
||||
* @event: The event, just happened.
|
||||
@@ -1012,7 +1012,7 @@ static void dev_action_start(fsm_instance *fi, int event, void *arg)
|
||||
fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Shutdown connection by sending CONN_EVENT_STOP to it.
|
||||
*
|
||||
* @param fi An instance of an interface statemachine.
|
||||
@@ -1034,7 +1034,7 @@ dev_action_stop(fsm_instance *fi, int event, void *arg)
|
||||
fsm_event(privptr->conn->fsm, CONN_EVENT_STOP, &ev);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Called from connection statemachine
|
||||
* when a connection is up and running.
|
||||
*
|
||||
@@ -1067,7 +1067,7 @@ dev_action_connup(fsm_instance *fi, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Called from connection statemachine
|
||||
* when a connection has been shutdown.
|
||||
*
|
||||
@@ -1107,7 +1107,7 @@ static const fsm_node dev_fsm[] = {
|
||||
|
||||
static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Transmit a packet.
|
||||
* This is a helper function for netiucv_tx().
|
||||
*
|
||||
@@ -1144,7 +1144,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
|
||||
spin_unlock_irqrestore(&conn->collect_lock, saveflags);
|
||||
} else {
|
||||
struct sk_buff *nskb = skb;
|
||||
/**
|
||||
/*
|
||||
* Copy the skb to a new allocated skb in lowmem only if the
|
||||
* data is located above 2G in memory or tailroom is < 2.
|
||||
*/
|
||||
@@ -1164,7 +1164,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
|
||||
}
|
||||
copied = 1;
|
||||
}
|
||||
/**
|
||||
/*
|
||||
* skb now is below 2G and has enough room. Add headers.
|
||||
*/
|
||||
header.next = nskb->len + NETIUCV_HDRLEN;
|
||||
@@ -1194,7 +1194,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
|
||||
if (copied)
|
||||
dev_kfree_skb(nskb);
|
||||
else {
|
||||
/**
|
||||
/*
|
||||
* Remove our headers. They get added
|
||||
* again on retransmit.
|
||||
*/
|
||||
@@ -1217,7 +1217,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
|
||||
* Interface API for upper network layers
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* Open an interface.
|
||||
* Called from generic network layer when ifconfig up is run.
|
||||
*
|
||||
@@ -1233,7 +1233,7 @@ static int netiucv_open(struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Close an interface.
|
||||
* Called from generic network layer when ifconfig down is run.
|
||||
*
|
||||
@@ -1249,7 +1249,7 @@ static int netiucv_close(struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Start transmission of a packet.
|
||||
* Called from generic network device layer.
|
||||
*
|
||||
@@ -1266,7 +1266,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
int rc;
|
||||
|
||||
IUCV_DBF_TEXT(trace, 4, __func__);
|
||||
/**
|
||||
/*
|
||||
* Some sanity checks ...
|
||||
*/
|
||||
if (skb == NULL) {
|
||||
@@ -1282,7 +1282,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* If connection is not running, try to restart it
|
||||
* and throw away packet.
|
||||
*/
|
||||
@@ -1304,7 +1304,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* netiucv_stats
|
||||
* @dev: Pointer to interface struct.
|
||||
*
|
||||
@@ -1745,7 +1745,7 @@ static void netiucv_unregister_device(struct device *dev)
|
||||
device_unregister(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Allocate and initialize a new connection structure.
|
||||
* Add it to the list of netiucv connections;
|
||||
*/
|
||||
@@ -1802,7 +1802,7 @@ out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Release a connection structure and remove it from the
|
||||
* list of netiucv connections.
|
||||
*/
|
||||
@@ -1826,7 +1826,7 @@ static void netiucv_remove_connection(struct iucv_connection *conn)
|
||||
kfree_skb(conn->tx_buff);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Release everything of a net device.
|
||||
*/
|
||||
static void netiucv_free_netdevice(struct net_device *dev)
|
||||
@@ -1848,7 +1848,7 @@ static void netiucv_free_netdevice(struct net_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Initialize a net device. (Called from kernel in alloc_netdev())
|
||||
*/
|
||||
static const struct net_device_ops netiucv_netdev_ops = {
|
||||
@@ -1873,7 +1873,7 @@ static void netiucv_setup_netdevice(struct net_device *dev)
|
||||
dev->netdev_ops = &netiucv_netdev_ops;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Allocate and initialize everything of a net device.
|
||||
*/
|
||||
static struct net_device *netiucv_init_netdevice(char *username, char *userdata)
|
||||
|
||||
@@ -145,12 +145,6 @@ struct qed_filter_mcast_params {
|
||||
unsigned char mac[64][ETH_ALEN];
|
||||
};
|
||||
|
||||
union qed_filter_type_params {
|
||||
enum qed_filter_rx_mode_type accept_flags;
|
||||
struct qed_filter_ucast_params ucast;
|
||||
struct qed_filter_mcast_params mcast;
|
||||
};
|
||||
|
||||
enum qed_filter_type {
|
||||
QED_FILTER_TYPE_UCAST,
|
||||
QED_FILTER_TYPE_MCAST,
|
||||
@@ -158,11 +152,6 @@ enum qed_filter_type {
|
||||
QED_MAX_FILTER_TYPES,
|
||||
};
|
||||
|
||||
struct qed_filter_params {
|
||||
enum qed_filter_type type;
|
||||
union qed_filter_type_params filter;
|
||||
};
|
||||
|
||||
struct qed_tunn_params {
|
||||
u16 vxlan_port;
|
||||
u8 update_vxlan_port;
|
||||
@@ -314,8 +303,14 @@ struct qed_eth_ops {
|
||||
|
||||
int (*q_tx_stop)(struct qed_dev *cdev, u8 rss_id, void *handle);
|
||||
|
||||
int (*filter_config)(struct qed_dev *cdev,
|
||||
struct qed_filter_params *params);
|
||||
int (*filter_config_rx_mode)(struct qed_dev *cdev,
|
||||
enum qed_filter_rx_mode_type type);
|
||||
|
||||
int (*filter_config_ucast)(struct qed_dev *cdev,
|
||||
struct qed_filter_ucast_params *params);
|
||||
|
||||
int (*filter_config_mcast)(struct qed_dev *cdev,
|
||||
struct qed_filter_mcast_params *params);
|
||||
|
||||
int (*fastpath_stop)(struct qed_dev *cdev);
|
||||
|
||||
|
||||
@@ -1653,10 +1653,6 @@ void devlink_param_unregister(struct devlink *devlink,
|
||||
const struct devlink_param *param);
|
||||
void devlink_params_publish(struct devlink *devlink);
|
||||
void devlink_params_unpublish(struct devlink *devlink);
|
||||
void devlink_param_publish(struct devlink *devlink,
|
||||
const struct devlink_param *param);
|
||||
void devlink_param_unpublish(struct devlink *devlink,
|
||||
const struct devlink_param *param);
|
||||
int devlink_port_params_register(struct devlink_port *devlink_port,
|
||||
const struct devlink_param *params,
|
||||
size_t params_count);
|
||||
|
||||
@@ -308,6 +308,8 @@ struct Qdisc_ops {
|
||||
struct netlink_ext_ack *extack);
|
||||
void (*attach)(struct Qdisc *sch);
|
||||
int (*change_tx_queue_len)(struct Qdisc *, unsigned int);
|
||||
void (*change_real_num_tx)(struct Qdisc *sch,
|
||||
unsigned int new_real_tx);
|
||||
|
||||
int (*dump)(struct Qdisc *, struct sk_buff *);
|
||||
int (*dump_stats)(struct Qdisc *, struct gnet_dump *);
|
||||
@@ -684,6 +686,8 @@ void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *);
|
||||
void qdisc_class_hash_destroy(struct Qdisc_class_hash *);
|
||||
|
||||
int dev_qdisc_change_tx_queue_len(struct net_device *dev);
|
||||
void dev_qdisc_change_real_num_tx(struct net_device *dev,
|
||||
unsigned int new_real_tx);
|
||||
void dev_init_scheduler(struct net_device *dev);
|
||||
void dev_shutdown(struct net_device *dev);
|
||||
void dev_activate(struct net_device *dev);
|
||||
|
||||
@@ -38,6 +38,9 @@ enum { /* SMC PNET Table commands */
|
||||
#define SMC_GENL_FAMILY_VERSION 1
|
||||
|
||||
#define SMC_PCI_ID_STR_LEN 16 /* Max length of pci id string */
|
||||
#define SMC_MAX_HOSTNAME_LEN 32 /* Max length of the hostname */
|
||||
#define SMC_MAX_UEID 4 /* Max number of user EIDs */
|
||||
#define SMC_MAX_EID_LEN 32 /* Max length of an EID */
|
||||
|
||||
/* SMC_GENL_FAMILY commands */
|
||||
enum {
|
||||
@@ -49,6 +52,13 @@ enum {
|
||||
SMC_NETLINK_GET_DEV_SMCR,
|
||||
SMC_NETLINK_GET_STATS,
|
||||
SMC_NETLINK_GET_FBACK_STATS,
|
||||
SMC_NETLINK_DUMP_UEID,
|
||||
SMC_NETLINK_ADD_UEID,
|
||||
SMC_NETLINK_REMOVE_UEID,
|
||||
SMC_NETLINK_FLUSH_UEID,
|
||||
SMC_NETLINK_DUMP_SEID,
|
||||
SMC_NETLINK_ENABLE_SEID,
|
||||
SMC_NETLINK_DISABLE_SEID,
|
||||
};
|
||||
|
||||
/* SMC_GENL_FAMILY top level attributes */
|
||||
@@ -242,4 +252,21 @@ enum {
|
||||
__SMC_NLA_FBACK_STATS_MAX,
|
||||
SMC_NLA_FBACK_STATS_MAX = __SMC_NLA_FBACK_STATS_MAX - 1
|
||||
};
|
||||
|
||||
/* SMC_NETLINK_UEID attributes */
|
||||
enum {
|
||||
SMC_NLA_EID_TABLE_UNSPEC,
|
||||
SMC_NLA_EID_TABLE_ENTRY, /* string */
|
||||
__SMC_NLA_EID_TABLE_MAX,
|
||||
SMC_NLA_EID_TABLE_MAX = __SMC_NLA_EID_TABLE_MAX - 1
|
||||
};
|
||||
|
||||
/* SMC_NETLINK_SEID attributes */
|
||||
enum {
|
||||
SMC_NLA_SEID_UNSPEC,
|
||||
SMC_NLA_SEID_ENTRY, /* string */
|
||||
SMC_NLA_SEID_ENABLED, /* u8 */
|
||||
__SMC_NLA_SEID_TABLE_MAX,
|
||||
SMC_NLA_SEID_TABLE_MAX = __SMC_NLA_SEID_TABLE_MAX - 1
|
||||
};
|
||||
#endif /* _UAPI_LINUX_SMC_H */
|
||||
|
||||
@@ -2928,6 +2928,8 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
|
||||
if (dev->num_tc)
|
||||
netif_setup_tc(dev, txq);
|
||||
|
||||
dev_qdisc_change_real_num_tx(dev, txq);
|
||||
|
||||
dev->real_num_tx_queues = txq;
|
||||
|
||||
if (disabling) {
|
||||
|
||||
@@ -10121,54 +10121,6 @@ void devlink_params_unpublish(struct devlink *devlink)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_params_unpublish);
|
||||
|
||||
/**
|
||||
* devlink_param_publish - publish one configuration parameter
|
||||
*
|
||||
* @devlink: devlink
|
||||
* @param: one configuration parameter
|
||||
*
|
||||
* Publish previously registered configuration parameter.
|
||||
*/
|
||||
void devlink_param_publish(struct devlink *devlink,
|
||||
const struct devlink_param *param)
|
||||
{
|
||||
struct devlink_param_item *param_item;
|
||||
|
||||
list_for_each_entry(param_item, &devlink->param_list, list) {
|
||||
if (param_item->param != param || param_item->published)
|
||||
continue;
|
||||
param_item->published = true;
|
||||
devlink_param_notify(devlink, 0, param_item,
|
||||
DEVLINK_CMD_PARAM_NEW);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_param_publish);
|
||||
|
||||
/**
|
||||
* devlink_param_unpublish - unpublish one configuration parameter
|
||||
*
|
||||
* @devlink: devlink
|
||||
* @param: one configuration parameter
|
||||
*
|
||||
* Unpublish previously registered configuration parameter.
|
||||
*/
|
||||
void devlink_param_unpublish(struct devlink *devlink,
|
||||
const struct devlink_param *param)
|
||||
{
|
||||
struct devlink_param_item *param_item;
|
||||
|
||||
list_for_each_entry(param_item, &devlink->param_list, list) {
|
||||
if (param_item->param != param || !param_item->published)
|
||||
continue;
|
||||
param_item->published = false;
|
||||
devlink_param_notify(devlink, 0, param_item,
|
||||
DEVLINK_CMD_PARAM_DEL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_param_unpublish);
|
||||
|
||||
/**
|
||||
* devlink_port_params_register - register port configuration parameters
|
||||
*
|
||||
|
||||
@@ -136,34 +136,31 @@ struct napi_alloc_cache {
|
||||
static DEFINE_PER_CPU(struct page_frag_cache, netdev_alloc_cache);
|
||||
static DEFINE_PER_CPU(struct napi_alloc_cache, napi_alloc_cache);
|
||||
|
||||
static void *__alloc_frag_align(unsigned int fragsz, gfp_t gfp_mask,
|
||||
unsigned int align_mask)
|
||||
void *__napi_alloc_frag_align(unsigned int fragsz, unsigned int align_mask)
|
||||
{
|
||||
struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
|
||||
|
||||
return page_frag_alloc_align(&nc->page, fragsz, gfp_mask, align_mask);
|
||||
}
|
||||
|
||||
void *__napi_alloc_frag_align(unsigned int fragsz, unsigned int align_mask)
|
||||
{
|
||||
fragsz = SKB_DATA_ALIGN(fragsz);
|
||||
|
||||
return __alloc_frag_align(fragsz, GFP_ATOMIC, align_mask);
|
||||
return page_frag_alloc_align(&nc->page, fragsz, GFP_ATOMIC, align_mask);
|
||||
}
|
||||
EXPORT_SYMBOL(__napi_alloc_frag_align);
|
||||
|
||||
void *__netdev_alloc_frag_align(unsigned int fragsz, unsigned int align_mask)
|
||||
{
|
||||
struct page_frag_cache *nc;
|
||||
void *data;
|
||||
|
||||
fragsz = SKB_DATA_ALIGN(fragsz);
|
||||
if (in_hardirq() || irqs_disabled()) {
|
||||
nc = this_cpu_ptr(&netdev_alloc_cache);
|
||||
struct page_frag_cache *nc = this_cpu_ptr(&netdev_alloc_cache);
|
||||
|
||||
data = page_frag_alloc_align(nc, fragsz, GFP_ATOMIC, align_mask);
|
||||
} else {
|
||||
struct napi_alloc_cache *nc;
|
||||
|
||||
local_bh_disable();
|
||||
data = __alloc_frag_align(fragsz, GFP_ATOMIC, align_mask);
|
||||
nc = this_cpu_ptr(&napi_alloc_cache);
|
||||
data = page_frag_alloc_align(&nc->page, fragsz, GFP_ATOMIC, align_mask);
|
||||
local_bh_enable();
|
||||
}
|
||||
return data;
|
||||
|
||||
@@ -54,7 +54,7 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
|
||||
p = (__be16 *)tag;
|
||||
*p = htons(RTL4_A_ETHERTYPE);
|
||||
|
||||
out = (RTL4_A_PROTOCOL_RTL8366RB << RTL4_A_PROTOCOL_SHIFT) | (2 << 8);
|
||||
out = (RTL4_A_PROTOCOL_RTL8366RB << RTL4_A_PROTOCOL_SHIFT);
|
||||
/* The lower bits indicate the port number */
|
||||
out |= BIT(dp->index);
|
||||
|
||||
|
||||
@@ -1537,6 +1537,10 @@ static int ethtool_get_any_eeprom(struct net_device *dev, void __user *useraddr,
|
||||
ret = getter(dev, &eeprom, data);
|
||||
if (ret)
|
||||
break;
|
||||
if (!eeprom.len) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
if (copy_to_user(userbuf, data, eeprom.len)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
|
||||
@@ -201,8 +201,7 @@ static void llc_shdlc_reset_t2(struct llc_shdlc *shdlc, int y_nr)
|
||||
del_timer_sync(&shdlc->t2_timer);
|
||||
shdlc->t2_active = false;
|
||||
|
||||
pr_debug
|
||||
("All sent frames acked. Stopped T2(retransmit)\n");
|
||||
pr_debug("All sent frames acked. Stopped T2(retransmit)\n");
|
||||
}
|
||||
} else {
|
||||
skb = skb_peek(&shdlc->ack_pending_q);
|
||||
@@ -211,8 +210,7 @@ static void llc_shdlc_reset_t2(struct llc_shdlc *shdlc, int y_nr)
|
||||
msecs_to_jiffies(SHDLC_T2_VALUE_MS));
|
||||
shdlc->t2_active = true;
|
||||
|
||||
pr_debug
|
||||
("Start T2(retransmit) for remaining unacked sent frames\n");
|
||||
pr_debug("Start T2(retransmit) for remaining unacked sent frames\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,12 +520,11 @@ static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc)
|
||||
unsigned long time_sent;
|
||||
|
||||
if (shdlc->send_q.qlen)
|
||||
pr_debug
|
||||
("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n",
|
||||
shdlc->send_q.qlen, shdlc->ns, shdlc->dnr,
|
||||
shdlc->rnr == false ? "false" : "true",
|
||||
shdlc->w - llc_shdlc_w_used(shdlc->ns, shdlc->dnr),
|
||||
shdlc->ack_pending_q.qlen);
|
||||
pr_debug("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n",
|
||||
shdlc->send_q.qlen, shdlc->ns, shdlc->dnr,
|
||||
shdlc->rnr == false ? "false" : "true",
|
||||
shdlc->w - llc_shdlc_w_used(shdlc->ns, shdlc->dnr),
|
||||
shdlc->ack_pending_q.qlen);
|
||||
|
||||
while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w &&
|
||||
(shdlc->rnr == false)) {
|
||||
@@ -649,8 +646,7 @@ static void llc_shdlc_sm_work(struct work_struct *work)
|
||||
llc_shdlc_handle_send_queue(shdlc);
|
||||
|
||||
if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) {
|
||||
pr_debug
|
||||
("Handle T1(send ack) elapsed (T1 now inactive)\n");
|
||||
pr_debug("Handle T1(send ack) elapsed (T1 now inactive)\n");
|
||||
|
||||
shdlc->t1_active = false;
|
||||
r = llc_shdlc_send_s_frame(shdlc, S_FRAME_RR,
|
||||
@@ -660,8 +656,7 @@ static void llc_shdlc_sm_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (shdlc->t2_active && timer_pending(&shdlc->t2_timer) == 0) {
|
||||
pr_debug
|
||||
("Handle T2(retransmit) elapsed (T2 inactive)\n");
|
||||
pr_debug("Handle T2(retransmit) elapsed (T2 inactive)\n");
|
||||
|
||||
shdlc->t2_active = false;
|
||||
|
||||
|
||||
@@ -1330,6 +1330,15 @@ static int qdisc_change_tx_queue_len(struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dev_qdisc_change_real_num_tx(struct net_device *dev,
|
||||
unsigned int new_real_tx)
|
||||
{
|
||||
struct Qdisc *qdisc = dev->qdisc;
|
||||
|
||||
if (qdisc->ops->change_real_num_tx)
|
||||
qdisc->ops->change_real_num_tx(qdisc, new_real_tx);
|
||||
}
|
||||
|
||||
int dev_qdisc_change_tx_queue_len(struct net_device *dev)
|
||||
{
|
||||
bool up = dev->flags & IFF_UP;
|
||||
|
||||
@@ -125,6 +125,29 @@ static void mq_attach(struct Qdisc *sch)
|
||||
priv->qdiscs = NULL;
|
||||
}
|
||||
|
||||
static void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx)
|
||||
{
|
||||
#ifdef CONFIG_NET_SCHED
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct Qdisc *qdisc;
|
||||
unsigned int i;
|
||||
|
||||
for (i = new_real_tx; i < dev->real_num_tx_queues; i++) {
|
||||
qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
|
||||
/* Only update the default qdiscs we created,
|
||||
* qdiscs with handles are always hashed.
|
||||
*/
|
||||
if (qdisc != &noop_qdisc && !qdisc->handle)
|
||||
qdisc_hash_del(qdisc);
|
||||
}
|
||||
for (i = dev->real_num_tx_queues; i < new_real_tx; i++) {
|
||||
qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
|
||||
if (qdisc != &noop_qdisc && !qdisc->handle)
|
||||
qdisc_hash_add(qdisc, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
@@ -288,6 +311,7 @@ struct Qdisc_ops mq_qdisc_ops __read_mostly = {
|
||||
.init = mq_init,
|
||||
.destroy = mq_destroy,
|
||||
.attach = mq_attach,
|
||||
.change_real_num_tx = mq_change_real_num_tx,
|
||||
.dump = mq_dump,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@@ -306,6 +306,28 @@ static void mqprio_attach(struct Qdisc *sch)
|
||||
priv->qdiscs = NULL;
|
||||
}
|
||||
|
||||
static void mqprio_change_real_num_tx(struct Qdisc *sch,
|
||||
unsigned int new_real_tx)
|
||||
{
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct Qdisc *qdisc;
|
||||
unsigned int i;
|
||||
|
||||
for (i = new_real_tx; i < dev->real_num_tx_queues; i++) {
|
||||
qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
|
||||
/* Only update the default qdiscs we created,
|
||||
* qdiscs with handles are always hashed.
|
||||
*/
|
||||
if (qdisc != &noop_qdisc && !qdisc->handle)
|
||||
qdisc_hash_del(qdisc);
|
||||
}
|
||||
for (i = dev->real_num_tx_queues; i < new_real_tx; i++) {
|
||||
qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
|
||||
if (qdisc != &noop_qdisc && !qdisc->handle)
|
||||
qdisc_hash_add(qdisc, false);
|
||||
}
|
||||
}
|
||||
|
||||
static struct netdev_queue *mqprio_queue_get(struct Qdisc *sch,
|
||||
unsigned long cl)
|
||||
{
|
||||
@@ -629,6 +651,7 @@ static struct Qdisc_ops mqprio_qdisc_ops __read_mostly = {
|
||||
.init = mqprio_init,
|
||||
.destroy = mqprio_destroy,
|
||||
.attach = mqprio_attach,
|
||||
.change_real_num_tx = mqprio_change_real_num_tx,
|
||||
.dump = mqprio_dump,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@@ -829,7 +829,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
|
||||
smc_rmb_sync_sg_for_device(&smc->conn);
|
||||
|
||||
reason_code = smc_clc_send_confirm(smc, ini->first_contact_local,
|
||||
SMC_V1);
|
||||
SMC_V1, NULL);
|
||||
if (reason_code)
|
||||
goto connect_abort;
|
||||
|
||||
@@ -883,6 +883,7 @@ static int smc_connect_ism(struct smc_sock *smc,
|
||||
struct smc_clc_msg_accept_confirm *aclc,
|
||||
struct smc_init_info *ini)
|
||||
{
|
||||
u8 *eid = NULL;
|
||||
int rc = 0;
|
||||
|
||||
ini->is_smcd = true;
|
||||
@@ -918,8 +919,15 @@ static int smc_connect_ism(struct smc_sock *smc,
|
||||
smc_rx_init(smc);
|
||||
smc_tx_init(smc);
|
||||
|
||||
if (aclc->hdr.version > SMC_V1) {
|
||||
struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
|
||||
(struct smc_clc_msg_accept_confirm_v2 *)aclc;
|
||||
|
||||
eid = clc_v2->eid;
|
||||
}
|
||||
|
||||
rc = smc_clc_send_confirm(smc, ini->first_contact_local,
|
||||
aclc->hdr.version);
|
||||
aclc->hdr.version, eid);
|
||||
if (rc)
|
||||
goto connect_abort;
|
||||
mutex_unlock(&smc_server_lgr_pending);
|
||||
@@ -1533,9 +1541,8 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
|
||||
pclc_smcd = smc_get_clc_msg_smcd(pclc);
|
||||
smc_v2_ext = smc_get_clc_v2_ext(pclc);
|
||||
smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext);
|
||||
if (!smcd_v2_ext ||
|
||||
!smc_v2_ext->hdr.flag.seid) { /* no system EID support for SMCD */
|
||||
smc_find_ism_store_rc(SMC_CLC_DECL_NOSEID, ini);
|
||||
if (!smcd_v2_ext) {
|
||||
smc_find_ism_store_rc(SMC_CLC_DECL_NOV2DEXT, ini);
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
@@ -1555,13 +1562,13 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
|
||||
}
|
||||
mutex_unlock(&smcd_dev_list.mutex);
|
||||
|
||||
if (ini->ism_dev[0]) {
|
||||
smc_ism_get_system_eid(ini->ism_dev[0], &eid);
|
||||
if (memcmp(eid, smcd_v2_ext->system_eid, SMC_MAX_EID_LEN))
|
||||
goto not_found;
|
||||
} else {
|
||||
if (!ini->ism_dev[0])
|
||||
goto not_found;
|
||||
|
||||
smc_ism_get_system_eid(&eid);
|
||||
if (!smc_clc_match_eid(ini->negotiated_eid, smc_v2_ext,
|
||||
smcd_v2_ext->system_eid, eid))
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
/* separate - outside the smcd_dev_list.lock */
|
||||
smcd_version = ini->smcd_version;
|
||||
@@ -1579,6 +1586,7 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
|
||||
}
|
||||
/* no V2 ISM device could be initialized */
|
||||
ini->smcd_version = smcd_version; /* restore original value */
|
||||
ini->negotiated_eid[0] = 0;
|
||||
|
||||
not_found:
|
||||
ini->smcd_version &= ~SMC_V2;
|
||||
@@ -1788,7 +1796,8 @@ static void smc_listen_work(struct work_struct *work)
|
||||
|
||||
/* send SMC Accept CLC message */
|
||||
rc = smc_clc_send_accept(new_smc, ini->first_contact_local,
|
||||
ini->smcd_version == SMC_V2 ? SMC_V2 : SMC_V1);
|
||||
ini->smcd_version == SMC_V2 ? SMC_V2 : SMC_V1,
|
||||
ini->negotiated_eid);
|
||||
if (rc)
|
||||
goto out_unlock;
|
||||
|
||||
@@ -2662,6 +2671,7 @@ static void __exit smc_exit(void)
|
||||
proto_unregister(&smc_proto);
|
||||
smc_pnet_exit();
|
||||
smc_nl_exit();
|
||||
smc_clc_exit();
|
||||
unregister_pernet_subsys(&smc_net_stat_ops);
|
||||
unregister_pernet_subsys(&smc_net_ops);
|
||||
rcu_barrier();
|
||||
|
||||
@@ -29,9 +29,6 @@
|
||||
* devices
|
||||
*/
|
||||
|
||||
#define SMC_MAX_HOSTNAME_LEN 32
|
||||
#define SMC_MAX_EID_LEN 32
|
||||
|
||||
extern struct proto smc_proto;
|
||||
extern struct proto smc_proto6;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "smc_clc.h"
|
||||
#include "smc_ib.h"
|
||||
#include "smc_ism.h"
|
||||
#include "smc_netlink.h"
|
||||
|
||||
#define SMCR_CLC_ACCEPT_CONFIRM_LEN 68
|
||||
#define SMCD_CLC_ACCEPT_CONFIRM_LEN 48
|
||||
@@ -39,6 +40,285 @@ static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
|
||||
|
||||
static u8 smc_hostname[SMC_MAX_HOSTNAME_LEN];
|
||||
|
||||
struct smc_clc_eid_table {
|
||||
rwlock_t lock;
|
||||
struct list_head list;
|
||||
u8 ueid_cnt;
|
||||
u8 seid_enabled;
|
||||
};
|
||||
|
||||
static struct smc_clc_eid_table smc_clc_eid_table;
|
||||
|
||||
struct smc_clc_eid_entry {
|
||||
struct list_head list;
|
||||
u8 eid[SMC_MAX_EID_LEN];
|
||||
};
|
||||
|
||||
/* The size of a user EID is 32 characters.
|
||||
* Valid characters should be (single-byte character set) A-Z, 0-9, '.' and '-'.
|
||||
* Blanks should only be used to pad to the expected size.
|
||||
* First character must be alphanumeric.
|
||||
*/
|
||||
static bool smc_clc_ueid_valid(char *ueid)
|
||||
{
|
||||
char *end = ueid + SMC_MAX_EID_LEN;
|
||||
|
||||
while (--end >= ueid && isspace(*end))
|
||||
;
|
||||
if (end < ueid)
|
||||
return false;
|
||||
if (!isalnum(*ueid) || islower(*ueid))
|
||||
return false;
|
||||
while (ueid <= end) {
|
||||
if ((!isalnum(*ueid) || islower(*ueid)) && *ueid != '.' &&
|
||||
*ueid != '-')
|
||||
return false;
|
||||
ueid++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int smc_clc_ueid_add(char *ueid)
|
||||
{
|
||||
struct smc_clc_eid_entry *new_ueid, *tmp_ueid;
|
||||
int rc;
|
||||
|
||||
if (!smc_clc_ueid_valid(ueid))
|
||||
return -EINVAL;
|
||||
|
||||
/* add a new ueid entry to the ueid table if there isn't one */
|
||||
new_ueid = kzalloc(sizeof(*new_ueid), GFP_KERNEL);
|
||||
if (!new_ueid)
|
||||
return -ENOMEM;
|
||||
memcpy(new_ueid->eid, ueid, SMC_MAX_EID_LEN);
|
||||
|
||||
write_lock(&smc_clc_eid_table.lock);
|
||||
if (smc_clc_eid_table.ueid_cnt >= SMC_MAX_UEID) {
|
||||
rc = -ERANGE;
|
||||
goto err_out;
|
||||
}
|
||||
list_for_each_entry(tmp_ueid, &smc_clc_eid_table.list, list) {
|
||||
if (!memcmp(tmp_ueid->eid, ueid, SMC_MAX_EID_LEN)) {
|
||||
rc = -EEXIST;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
list_add_tail(&new_ueid->list, &smc_clc_eid_table.list);
|
||||
smc_clc_eid_table.ueid_cnt++;
|
||||
write_unlock(&smc_clc_eid_table.lock);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
write_unlock(&smc_clc_eid_table.lock);
|
||||
kfree(new_ueid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int smc_nl_add_ueid(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr *nla_ueid = info->attrs[SMC_NLA_EID_TABLE_ENTRY];
|
||||
char *ueid;
|
||||
|
||||
if (!nla_ueid || nla_len(nla_ueid) != SMC_MAX_EID_LEN + 1)
|
||||
return -EINVAL;
|
||||
ueid = (char *)nla_data(nla_ueid);
|
||||
|
||||
return smc_clc_ueid_add(ueid);
|
||||
}
|
||||
|
||||
/* remove one or all ueid entries from the table */
|
||||
static int smc_clc_ueid_remove(char *ueid)
|
||||
{
|
||||
struct smc_clc_eid_entry *lst_ueid, *tmp_ueid;
|
||||
int rc = -ENOENT;
|
||||
|
||||
/* remove table entry */
|
||||
write_lock(&smc_clc_eid_table.lock);
|
||||
list_for_each_entry_safe(lst_ueid, tmp_ueid, &smc_clc_eid_table.list,
|
||||
list) {
|
||||
if (!ueid || !memcmp(lst_ueid->eid, ueid, SMC_MAX_EID_LEN)) {
|
||||
list_del(&lst_ueid->list);
|
||||
smc_clc_eid_table.ueid_cnt--;
|
||||
kfree(lst_ueid);
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
if (!rc && !smc_clc_eid_table.ueid_cnt) {
|
||||
smc_clc_eid_table.seid_enabled = 1;
|
||||
rc = -EAGAIN; /* indicate success and enabling of seid */
|
||||
}
|
||||
write_unlock(&smc_clc_eid_table.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int smc_nl_remove_ueid(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr *nla_ueid = info->attrs[SMC_NLA_EID_TABLE_ENTRY];
|
||||
char *ueid;
|
||||
|
||||
if (!nla_ueid || nla_len(nla_ueid) != SMC_MAX_EID_LEN + 1)
|
||||
return -EINVAL;
|
||||
ueid = (char *)nla_data(nla_ueid);
|
||||
|
||||
return smc_clc_ueid_remove(ueid);
|
||||
}
|
||||
|
||||
int smc_nl_flush_ueid(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
smc_clc_ueid_remove(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smc_nl_ueid_dumpinfo(struct sk_buff *skb, u32 portid, u32 seq,
|
||||
u32 flags, char *ueid)
|
||||
{
|
||||
char ueid_str[SMC_MAX_EID_LEN + 1];
|
||||
void *hdr;
|
||||
|
||||
hdr = genlmsg_put(skb, portid, seq, &smc_gen_nl_family,
|
||||
flags, SMC_NETLINK_DUMP_UEID);
|
||||
if (!hdr)
|
||||
return -ENOMEM;
|
||||
snprintf(ueid_str, sizeof(ueid_str), "%s", ueid);
|
||||
if (nla_put_string(skb, SMC_NLA_EID_TABLE_ENTRY, ueid_str)) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
genlmsg_end(skb, hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _smc_nl_ueid_dump(struct sk_buff *skb, u32 portid, u32 seq,
|
||||
int start_idx)
|
||||
{
|
||||
struct smc_clc_eid_entry *lst_ueid;
|
||||
int idx = 0;
|
||||
|
||||
read_lock(&smc_clc_eid_table.lock);
|
||||
list_for_each_entry(lst_ueid, &smc_clc_eid_table.list, list) {
|
||||
if (idx++ < start_idx)
|
||||
continue;
|
||||
if (smc_nl_ueid_dumpinfo(skb, portid, seq, NLM_F_MULTI,
|
||||
lst_ueid->eid)) {
|
||||
--idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&smc_clc_eid_table.lock);
|
||||
return idx;
|
||||
}
|
||||
|
||||
int smc_nl_dump_ueid(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb);
|
||||
int idx;
|
||||
|
||||
idx = _smc_nl_ueid_dump(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, cb_ctx->pos[0]);
|
||||
|
||||
cb_ctx->pos[0] = idx;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
int smc_nl_dump_seid(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb);
|
||||
char seid_str[SMC_MAX_EID_LEN + 1];
|
||||
u8 seid_enabled;
|
||||
void *hdr;
|
||||
u8 *seid;
|
||||
|
||||
if (cb_ctx->pos[0])
|
||||
return skb->len;
|
||||
|
||||
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
||||
&smc_gen_nl_family, NLM_F_MULTI,
|
||||
SMC_NETLINK_DUMP_SEID);
|
||||
if (!hdr)
|
||||
return -ENOMEM;
|
||||
if (!smc_ism_is_v2_capable())
|
||||
goto end;
|
||||
|
||||
smc_ism_get_system_eid(&seid);
|
||||
snprintf(seid_str, sizeof(seid_str), "%s", seid);
|
||||
if (nla_put_string(skb, SMC_NLA_SEID_ENTRY, seid_str))
|
||||
goto err;
|
||||
read_lock(&smc_clc_eid_table.lock);
|
||||
seid_enabled = smc_clc_eid_table.seid_enabled;
|
||||
read_unlock(&smc_clc_eid_table.lock);
|
||||
if (nla_put_u8(skb, SMC_NLA_SEID_ENABLED, seid_enabled))
|
||||
goto err;
|
||||
end:
|
||||
genlmsg_end(skb, hdr);
|
||||
cb_ctx->pos[0]++;
|
||||
return skb->len;
|
||||
err:
|
||||
genlmsg_cancel(skb, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
int smc_nl_enable_seid(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
write_lock(&smc_clc_eid_table.lock);
|
||||
smc_clc_eid_table.seid_enabled = 1;
|
||||
write_unlock(&smc_clc_eid_table.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smc_nl_disable_seid(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
write_lock(&smc_clc_eid_table.lock);
|
||||
if (!smc_clc_eid_table.ueid_cnt)
|
||||
rc = -ENOENT;
|
||||
else
|
||||
smc_clc_eid_table.seid_enabled = 0;
|
||||
write_unlock(&smc_clc_eid_table.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool _smc_clc_match_ueid(u8 *peer_ueid)
|
||||
{
|
||||
struct smc_clc_eid_entry *tmp_ueid;
|
||||
|
||||
list_for_each_entry(tmp_ueid, &smc_clc_eid_table.list, list) {
|
||||
if (!memcmp(tmp_ueid->eid, peer_ueid, SMC_MAX_EID_LEN))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool smc_clc_match_eid(u8 *negotiated_eid,
|
||||
struct smc_clc_v2_extension *smc_v2_ext,
|
||||
u8 *peer_eid, u8 *local_eid)
|
||||
{
|
||||
bool match = false;
|
||||
int i;
|
||||
|
||||
negotiated_eid[0] = 0;
|
||||
read_lock(&smc_clc_eid_table.lock);
|
||||
if (smc_clc_eid_table.seid_enabled &&
|
||||
smc_v2_ext->hdr.flag.seid &&
|
||||
!memcmp(peer_eid, local_eid, SMC_MAX_EID_LEN)) {
|
||||
memcpy(negotiated_eid, peer_eid, SMC_MAX_EID_LEN);
|
||||
match = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < smc_v2_ext->hdr.eid_cnt; i++) {
|
||||
if (_smc_clc_match_ueid(smc_v2_ext->user_eids[i])) {
|
||||
memcpy(negotiated_eid, smc_v2_ext->user_eids[i],
|
||||
SMC_MAX_EID_LEN);
|
||||
match = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
read_unlock(&smc_clc_eid_table.lock);
|
||||
return match;
|
||||
}
|
||||
|
||||
/* check arriving CLC proposal */
|
||||
static bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc)
|
||||
{
|
||||
@@ -551,6 +831,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
|
||||
if (ini->smc_type_v2 == SMC_TYPE_N) {
|
||||
pclc_smcd->v2_ext_offset = 0;
|
||||
} else {
|
||||
struct smc_clc_eid_entry *ueident;
|
||||
u16 v2_ext_offset;
|
||||
u8 *eid = NULL;
|
||||
|
||||
@@ -561,19 +842,25 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
|
||||
pclc_prfx->ipv6_prefixes_cnt *
|
||||
sizeof(ipv6_prfx[0]);
|
||||
pclc_smcd->v2_ext_offset = htons(v2_ext_offset);
|
||||
v2_ext->hdr.eid_cnt = 0;
|
||||
|
||||
read_lock(&smc_clc_eid_table.lock);
|
||||
v2_ext->hdr.eid_cnt = smc_clc_eid_table.ueid_cnt;
|
||||
plen += smc_clc_eid_table.ueid_cnt * SMC_MAX_EID_LEN;
|
||||
i = 0;
|
||||
list_for_each_entry(ueident, &smc_clc_eid_table.list, list) {
|
||||
memcpy(v2_ext->user_eids[i++], ueident->eid,
|
||||
sizeof(ueident->eid));
|
||||
}
|
||||
v2_ext->hdr.flag.seid = smc_clc_eid_table.seid_enabled;
|
||||
read_unlock(&smc_clc_eid_table.lock);
|
||||
v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt;
|
||||
v2_ext->hdr.flag.release = SMC_RELEASE;
|
||||
v2_ext->hdr.flag.seid = 1;
|
||||
v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) -
|
||||
offsetofend(struct smc_clnt_opts_area_hdr,
|
||||
smcd_v2_ext_offset) +
|
||||
v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN);
|
||||
if (ini->ism_dev[0])
|
||||
smc_ism_get_system_eid(ini->ism_dev[0], &eid);
|
||||
else
|
||||
smc_ism_get_system_eid(ini->ism_dev[1], &eid);
|
||||
if (eid)
|
||||
smc_ism_get_system_eid(&eid);
|
||||
if (eid && v2_ext->hdr.flag.seid)
|
||||
memcpy(smcd_v2_ext->system_eid, eid, SMC_MAX_EID_LEN);
|
||||
plen += sizeof(*v2_ext) + sizeof(*smcd_v2_ext);
|
||||
if (ini->ism_offered_cnt) {
|
||||
@@ -608,7 +895,8 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
|
||||
}
|
||||
if (ini->smc_type_v2 != SMC_TYPE_N) {
|
||||
vec[i].iov_base = v2_ext;
|
||||
vec[i++].iov_len = sizeof(*v2_ext);
|
||||
vec[i++].iov_len = sizeof(*v2_ext) +
|
||||
(v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN);
|
||||
vec[i].iov_base = smcd_v2_ext;
|
||||
vec[i++].iov_len = sizeof(*smcd_v2_ext);
|
||||
if (ini->ism_offered_cnt) {
|
||||
@@ -636,7 +924,8 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
|
||||
/* build and send CLC CONFIRM / ACCEPT message */
|
||||
static int smc_clc_send_confirm_accept(struct smc_sock *smc,
|
||||
struct smc_clc_msg_accept_confirm_v2 *clc_v2,
|
||||
int first_contact, u8 version)
|
||||
int first_contact, u8 version,
|
||||
u8 *eid)
|
||||
{
|
||||
struct smc_connection *conn = &smc->conn;
|
||||
struct smc_clc_msg_accept_confirm *clc;
|
||||
@@ -664,11 +953,8 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
|
||||
if (version == SMC_V1) {
|
||||
clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
|
||||
} else {
|
||||
u8 *eid = NULL;
|
||||
|
||||
clc_v2->chid = htons(smc_ism_get_chid(conn->lgr->smcd));
|
||||
smc_ism_get_system_eid(conn->lgr->smcd, &eid);
|
||||
if (eid)
|
||||
if (eid[0])
|
||||
memcpy(clc_v2->eid, eid, SMC_MAX_EID_LEN);
|
||||
len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
|
||||
if (first_contact)
|
||||
@@ -733,7 +1019,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
|
||||
|
||||
/* send CLC CONFIRM message across internal TCP socket */
|
||||
int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
|
||||
u8 version)
|
||||
u8 version, u8 *eid)
|
||||
{
|
||||
struct smc_clc_msg_accept_confirm_v2 cclc_v2;
|
||||
int reason_code = 0;
|
||||
@@ -743,7 +1029,7 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
|
||||
memset(&cclc_v2, 0, sizeof(cclc_v2));
|
||||
cclc_v2.hdr.type = SMC_CLC_CONFIRM;
|
||||
len = smc_clc_send_confirm_accept(smc, &cclc_v2, clnt_first_contact,
|
||||
version);
|
||||
version, eid);
|
||||
if (len < ntohs(cclc_v2.hdr.length)) {
|
||||
if (len >= 0) {
|
||||
reason_code = -ENETUNREACH;
|
||||
@@ -758,7 +1044,7 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
|
||||
|
||||
/* send CLC ACCEPT message across internal TCP socket */
|
||||
int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
|
||||
u8 version)
|
||||
u8 version, u8 *negotiated_eid)
|
||||
{
|
||||
struct smc_clc_msg_accept_confirm_v2 aclc_v2;
|
||||
int len;
|
||||
@@ -766,7 +1052,7 @@ int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
|
||||
memset(&aclc_v2, 0, sizeof(aclc_v2));
|
||||
aclc_v2.hdr.type = SMC_CLC_ACCEPT;
|
||||
len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact,
|
||||
version);
|
||||
version, negotiated_eid);
|
||||
if (len < ntohs(aclc_v2.hdr.length))
|
||||
len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err;
|
||||
|
||||
@@ -786,4 +1072,14 @@ void __init smc_clc_init(void)
|
||||
u = utsname();
|
||||
memcpy(smc_hostname, u->nodename,
|
||||
min_t(size_t, strlen(u->nodename), sizeof(smc_hostname)));
|
||||
|
||||
INIT_LIST_HEAD(&smc_clc_eid_table.list);
|
||||
rwlock_init(&smc_clc_eid_table.lock);
|
||||
smc_clc_eid_table.ueid_cnt = 0;
|
||||
smc_clc_eid_table.seid_enabled = 1;
|
||||
}
|
||||
|
||||
void smc_clc_exit(void)
|
||||
{
|
||||
smc_clc_ueid_remove(NULL);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
#define _SMC_CLC_H
|
||||
|
||||
#include <rdma/ib_verbs.h>
|
||||
#include <linux/smc.h>
|
||||
|
||||
#include "smc.h"
|
||||
#include "smc_netlink.h"
|
||||
|
||||
#define SMC_CLC_PROPOSAL 0x01
|
||||
#define SMC_CLC_ACCEPT 0x02
|
||||
@@ -158,6 +160,7 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */
|
||||
} __aligned(4);
|
||||
|
||||
#define SMC_CLC_MAX_V6_PREFIX 8
|
||||
#define SMC_CLC_MAX_UEID 8
|
||||
|
||||
struct smc_clc_msg_proposal_area {
|
||||
struct smc_clc_msg_proposal pclc_base;
|
||||
@@ -165,6 +168,7 @@ struct smc_clc_msg_proposal_area {
|
||||
struct smc_clc_msg_proposal_prefix pclc_prfx;
|
||||
struct smc_clc_ipv6_prefix pclc_prfx_ipv6[SMC_CLC_MAX_V6_PREFIX];
|
||||
struct smc_clc_v2_extension pclc_v2_ext;
|
||||
u8 user_eids[SMC_CLC_MAX_UEID][SMC_MAX_EID_LEN];
|
||||
struct smc_clc_smcd_v2_extension pclc_smcd_v2_ext;
|
||||
struct smc_clc_smcd_gid_chid pclc_gidchids[SMC_MAX_ISM_DEVS];
|
||||
struct smc_clc_msg_trail pclc_trl;
|
||||
@@ -330,10 +334,21 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
|
||||
int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info, u8 version);
|
||||
int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini);
|
||||
int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
|
||||
u8 version);
|
||||
u8 version, u8 *eid);
|
||||
int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact,
|
||||
u8 version);
|
||||
u8 version, u8 *negotiated_eid);
|
||||
void smc_clc_init(void) __init;
|
||||
void smc_clc_exit(void);
|
||||
void smc_clc_get_hostname(u8 **host);
|
||||
bool smc_clc_match_eid(u8 *negotiated_eid,
|
||||
struct smc_clc_v2_extension *smc_v2_ext,
|
||||
u8 *peer_eid, u8 *local_eid);
|
||||
int smc_nl_dump_ueid(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int smc_nl_add_ueid(struct sk_buff *skb, struct genl_info *info);
|
||||
int smc_nl_remove_ueid(struct sk_buff *skb, struct genl_info *info);
|
||||
int smc_nl_flush_ueid(struct sk_buff *skb, struct genl_info *info);
|
||||
int smc_nl_dump_seid(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int smc_nl_enable_seid(struct sk_buff *skb, struct genl_info *info);
|
||||
int smc_nl_disable_seid(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -223,7 +223,6 @@ int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb);
|
||||
char hostname[SMC_MAX_HOSTNAME_LEN + 1];
|
||||
char smc_seid[SMC_MAX_EID_LEN + 1];
|
||||
struct smcd_dev *smcd_dev;
|
||||
struct nlattr *attrs;
|
||||
u8 *seid = NULL;
|
||||
u8 *host = NULL;
|
||||
@@ -252,13 +251,8 @@ int smc_nl_get_sys_info(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (nla_put_string(skb, SMC_NLA_SYS_LOCAL_HOST, hostname))
|
||||
goto errattr;
|
||||
}
|
||||
mutex_lock(&smcd_dev_list.mutex);
|
||||
smcd_dev = list_first_entry_or_null(&smcd_dev_list.list,
|
||||
struct smcd_dev, list);
|
||||
if (smcd_dev)
|
||||
smc_ism_get_system_eid(smcd_dev, &seid);
|
||||
mutex_unlock(&smcd_dev_list.mutex);
|
||||
if (seid && smc_ism_is_v2_capable()) {
|
||||
if (smc_ism_is_v2_capable()) {
|
||||
smc_ism_get_system_eid(&seid);
|
||||
memcpy(smc_seid, seid, SMC_MAX_EID_LEN);
|
||||
smc_seid[SMC_MAX_EID_LEN] = 0;
|
||||
if (nla_put_string(skb, SMC_NLA_SYS_SEID, smc_seid))
|
||||
|
||||
@@ -310,6 +310,7 @@ struct smc_init_info {
|
||||
u8 first_contact_local;
|
||||
unsigned short vlan_id;
|
||||
u32 rc;
|
||||
u8 negotiated_eid[SMC_MAX_EID_LEN];
|
||||
/* SMC-R */
|
||||
struct smc_clc_msg_local *ib_lcl;
|
||||
struct smc_ib_device *ib_dev;
|
||||
|
||||
@@ -23,6 +23,7 @@ struct smcd_dev_list smcd_dev_list = {
|
||||
};
|
||||
|
||||
static bool smc_ism_v2_capable;
|
||||
static u8 smc_ism_v2_system_eid[SMC_MAX_EID_LEN];
|
||||
|
||||
/* Test if an ISM communication is possible - same CPC */
|
||||
int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
|
||||
@@ -42,9 +43,12 @@ int smc_ism_write(struct smcd_dev *smcd, const struct smc_ism_position *pos,
|
||||
return rc < 0 ? rc : 0;
|
||||
}
|
||||
|
||||
void smc_ism_get_system_eid(struct smcd_dev *smcd, u8 **eid)
|
||||
void smc_ism_get_system_eid(u8 **eid)
|
||||
{
|
||||
smcd->ops->get_system_eid(smcd, eid);
|
||||
if (!smc_ism_v2_capable)
|
||||
*eid = NULL;
|
||||
else
|
||||
*eid = smc_ism_v2_system_eid;
|
||||
}
|
||||
|
||||
u16 smc_ism_get_chid(struct smcd_dev *smcd)
|
||||
@@ -435,9 +439,12 @@ int smcd_register_dev(struct smcd_dev *smcd)
|
||||
if (list_empty(&smcd_dev_list.list)) {
|
||||
u8 *system_eid = NULL;
|
||||
|
||||
smc_ism_get_system_eid(smcd, &system_eid);
|
||||
if (system_eid[24] != '0' || system_eid[28] != '0')
|
||||
smcd->ops->get_system_eid(smcd, &system_eid);
|
||||
if (system_eid[24] != '0' || system_eid[28] != '0') {
|
||||
smc_ism_v2_capable = true;
|
||||
memcpy(smc_ism_v2_system_eid, system_eid,
|
||||
SMC_MAX_EID_LEN);
|
||||
}
|
||||
}
|
||||
/* sort list: devices without pnetid before devices with pnetid */
|
||||
if (smcd->pnetid[0])
|
||||
@@ -533,4 +540,5 @@ EXPORT_SYMBOL_GPL(smcd_handle_irq);
|
||||
void __init smc_ism_init(void)
|
||||
{
|
||||
smc_ism_v2_capable = false;
|
||||
memset(smc_ism_v2_system_eid, 0, SMC_MAX_EID_LEN);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc);
|
||||
int smc_ism_write(struct smcd_dev *dev, const struct smc_ism_position *pos,
|
||||
void *data, size_t len);
|
||||
int smc_ism_signal_shutdown(struct smc_link_group *lgr);
|
||||
void smc_ism_get_system_eid(struct smcd_dev *dev, u8 **eid);
|
||||
void smc_ism_get_system_eid(u8 **eid);
|
||||
u16 smc_ism_get_chid(struct smcd_dev *dev);
|
||||
bool smc_ism_is_v2_capable(void);
|
||||
void smc_ism_init(void);
|
||||
|
||||
@@ -19,11 +19,19 @@
|
||||
#include "smc_core.h"
|
||||
#include "smc_ism.h"
|
||||
#include "smc_ib.h"
|
||||
#include "smc_clc.h"
|
||||
#include "smc_stats.h"
|
||||
#include "smc_netlink.h"
|
||||
|
||||
#define SMC_CMD_MAX_ATTR 1
|
||||
const struct nla_policy
|
||||
smc_gen_ueid_policy[SMC_NLA_EID_TABLE_MAX + 1] = {
|
||||
[SMC_NLA_EID_TABLE_UNSPEC] = { .type = NLA_UNSPEC },
|
||||
[SMC_NLA_EID_TABLE_ENTRY] = { .type = NLA_STRING,
|
||||
.len = SMC_MAX_EID_LEN,
|
||||
},
|
||||
};
|
||||
|
||||
#define SMC_CMD_MAX_ATTR 1
|
||||
/* SMC_GENL generic netlink operation definition */
|
||||
static const struct genl_ops smc_gen_nl_ops[] = {
|
||||
{
|
||||
@@ -66,6 +74,43 @@ static const struct genl_ops smc_gen_nl_ops[] = {
|
||||
/* can be retrieved by unprivileged users */
|
||||
.dumpit = smc_nl_get_fback_stats,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_DUMP_UEID,
|
||||
/* can be retrieved by unprivileged users */
|
||||
.dumpit = smc_nl_dump_ueid,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_ADD_UEID,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = smc_nl_add_ueid,
|
||||
.policy = smc_gen_ueid_policy,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_REMOVE_UEID,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = smc_nl_remove_ueid,
|
||||
.policy = smc_gen_ueid_policy,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_FLUSH_UEID,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = smc_nl_flush_ueid,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_DUMP_SEID,
|
||||
/* can be retrieved by unprivileged users */
|
||||
.dumpit = smc_nl_dump_seid,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_ENABLE_SEID,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = smc_nl_enable_seid,
|
||||
},
|
||||
{
|
||||
.cmd = SMC_NETLINK_DISABLE_SEID,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.doit = smc_nl_disable_seid,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct nla_policy smc_gen_nl_policy[2] = {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
extern struct genl_family smc_gen_nl_family;
|
||||
|
||||
extern const struct nla_policy smc_gen_ueid_policy[];
|
||||
|
||||
struct smc_nl_dmp_ctx {
|
||||
int pos[3];
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ function make_netdev {
|
||||
modprobe netdevsim
|
||||
fi
|
||||
|
||||
echo $NSIM_ID > /sys/bus/netdevsim/new_device
|
||||
echo $NSIM_ID $@ > /sys/bus/netdevsim/new_device
|
||||
# get new device name
|
||||
ls /sys/bus/netdevsim/devices/netdevsim${NSIM_ID}/net/
|
||||
}
|
||||
|
||||
77
tools/testing/selftests/drivers/net/netdevsim/tc-mq-visibility.sh
Executable file
77
tools/testing/selftests/drivers/net/netdevsim/tc-mq-visibility.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
source ethtool-common.sh
|
||||
|
||||
set -o pipefail
|
||||
|
||||
n_children() {
|
||||
n=$(tc qdisc show dev $NDEV | grep '^qdisc' | wc -l)
|
||||
echo $((n - 1))
|
||||
}
|
||||
|
||||
tcq() {
|
||||
tc qdisc $1 dev $NDEV ${@:2}
|
||||
}
|
||||
|
||||
n_child_assert() {
|
||||
n=$(n_children)
|
||||
if [ $n -ne $1 ]; then
|
||||
echo "ERROR ($root): ${@:2}, expected $1 have $n"
|
||||
((num_errors++))
|
||||
else
|
||||
((num_passes++))
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
for root in mq mqprio; do
|
||||
NDEV=$(make_netdev 1 4)
|
||||
|
||||
opts=
|
||||
[ $root == "mqprio" ] && opts='hw 0 num_tc 1 map 0 0 0 0 queues 1@0'
|
||||
|
||||
tcq add root handle 100: $root $opts
|
||||
n_child_assert 4 'Init'
|
||||
|
||||
# All defaults
|
||||
|
||||
for n in 3 2 1 2 3 4 1 4; do
|
||||
ethtool -L $NDEV combined $n
|
||||
n_child_assert $n "Change queues to $n while down"
|
||||
done
|
||||
|
||||
ip link set dev $NDEV up
|
||||
|
||||
for n in 3 2 1 2 3 4 1 4; do
|
||||
ethtool -L $NDEV combined $n
|
||||
n_child_assert $n "Change queues to $n while up"
|
||||
done
|
||||
|
||||
# One real one
|
||||
tcq replace parent 100:4 handle 204: pfifo_fast
|
||||
n_child_assert 4 "One real queue"
|
||||
|
||||
ethtool -L $NDEV combined 1
|
||||
n_child_assert 2 "One real queue, one default"
|
||||
|
||||
ethtool -L $NDEV combined 4
|
||||
n_child_assert 4 "One real queue, rest default"
|
||||
|
||||
# Graft some
|
||||
tcq replace parent 100:1 handle 204:
|
||||
n_child_assert 3 "Grafted"
|
||||
|
||||
ethtool -L $NDEV combined 1
|
||||
n_child_assert 1 "Grafted, one"
|
||||
|
||||
cleanup_nsim
|
||||
done
|
||||
|
||||
if [ $num_errors -eq 0 ]; then
|
||||
echo "PASSED all $((num_passes)) checks"
|
||||
exit 0
|
||||
else
|
||||
echo "FAILED $num_errors/$((num_errors+num_passes)) checks"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user