Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller:
1) Fix error path in netdevsim, from Jakub Kicinski.
2) Default values listed in tcp_wmem and tcp_rmem documentation were
inaccurate, from Tonghao Zhang.
3) Fix route leaks in SCTP, both for ipv4 and ipv6. From Alexey Kodanev
and Tommi Rantala.
4) Fix "MASK < Y" meant to be "MASK << Y" in xgbe driver, from Wolfram
Sang.
5) Use after free in u32_destroy_key(), from Paolo Abeni.
6) Fix two TX issues in be2net driver, from Suredh Reddy.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (25 commits)
be2net: Handle transmit completion errors in Lancer
be2net: Fix HW stall issue in Lancer
RDS: IB: Fix null pointer issue
nfp: fix kdoc warnings on nested structures
sample/bpf: fix erspan metadata
net: erspan: fix erspan config overwrite
net: erspan: fix metadata extraction
cls_u32: fix use after free in u32_destroy_key()
net: amd-xgbe: fix comparison to bitshift when dealing with a mask
net: phy: Handle not having GPIO enabled in the kernel
ibmvnic: fix empty firmware version and errors cleanup
sctp: fix dst refcnt leak in sctp_v4_get_dst
sctp: fix dst refcnt leak in sctp_v6_get_dst()
dwc-xlgmac: remove Jie Deng as co-maintainer
doc: Change the min default value of tcp_wmem/tcp_rmem.
samples/bpf: use bpf_set_link_xdp_fd
libbpf: add missing SPDX-License-Identifier
libbpf: add error reporting in XDP
libbpf: add function to setup XDP
tools: add netlink.h and if_link.h in tools uapi
...
This commit is contained in:
@@ -595,7 +595,7 @@ isr_done:
|
||||
|
||||
reissue_mask = 1 << 0;
|
||||
if (!pdata->per_channel_irq)
|
||||
reissue_mask |= 0xffff < 4;
|
||||
reissue_mask |= 0xffff << 4;
|
||||
|
||||
XP_IOWRITE(pdata, XP_INT_REISSUE_EN, reissue_mask);
|
||||
}
|
||||
|
||||
@@ -248,6 +248,7 @@ struct be_tx_stats {
|
||||
u32 tx_spoof_check_err;
|
||||
u32 tx_qinq_err;
|
||||
u32 tx_internal_parity_err;
|
||||
u32 tx_sge_err;
|
||||
struct u64_stats_sync sync;
|
||||
struct u64_stats_sync sync_compl;
|
||||
};
|
||||
@@ -944,8 +945,10 @@ static inline bool is_ipv6_ext_hdr(struct sk_buff *skb)
|
||||
#define BE_ERROR_EEH 1
|
||||
#define BE_ERROR_UE BIT(1)
|
||||
#define BE_ERROR_FW BIT(2)
|
||||
#define BE_ERROR_HW (BE_ERROR_EEH | BE_ERROR_UE)
|
||||
#define BE_ERROR_ANY (BE_ERROR_EEH | BE_ERROR_UE | BE_ERROR_FW)
|
||||
#define BE_ERROR_TX BIT(3)
|
||||
#define BE_ERROR_HW (BE_ERROR_EEH | BE_ERROR_UE | BE_ERROR_TX)
|
||||
#define BE_ERROR_ANY (BE_ERROR_EEH | BE_ERROR_UE | BE_ERROR_FW | \
|
||||
BE_ERROR_TX)
|
||||
#define BE_CLEAR_ALL 0xFF
|
||||
|
||||
static inline u8 be_check_error(struct be_adapter *adapter, u32 err_type)
|
||||
|
||||
@@ -189,6 +189,7 @@ static const struct be_ethtool_stat et_tx_stats[] = {
|
||||
* packet data. This counter is applicable only for Lancer adapters.
|
||||
*/
|
||||
{DRVSTAT_TX_INFO(tx_internal_parity_err)},
|
||||
{DRVSTAT_TX_INFO(tx_sge_err)},
|
||||
{DRVSTAT_TX_INFO(tx_bytes)},
|
||||
{DRVSTAT_TX_INFO(tx_pkts)},
|
||||
{DRVSTAT_TX_INFO(tx_vxlan_offload_pkts)},
|
||||
|
||||
@@ -261,6 +261,7 @@ struct be_eth_hdr_wrb {
|
||||
#define LANCER_TX_COMP_HSW_DROP_MAC_ERR 0x3
|
||||
#define LANCER_TX_COMP_HSW_DROP_VLAN_ERR 0x5
|
||||
#define LANCER_TX_COMP_QINQ_ERR 0x7
|
||||
#define LANCER_TX_COMP_SGE_ERR 0x9
|
||||
#define LANCER_TX_COMP_PARITY_ERR 0xb
|
||||
#define LANCER_TX_COMP_DMA_ERR 0xd
|
||||
|
||||
|
||||
@@ -2583,7 +2583,48 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp, u32 frags_needed)
|
||||
}
|
||||
}
|
||||
|
||||
static struct be_tx_compl_info *be_tx_compl_get(struct be_tx_obj *txo)
|
||||
static inline void be_update_tx_err(struct be_tx_obj *txo, u8 status)
|
||||
{
|
||||
switch (status) {
|
||||
case BE_TX_COMP_HDR_PARSE_ERR:
|
||||
tx_stats(txo)->tx_hdr_parse_err++;
|
||||
break;
|
||||
case BE_TX_COMP_NDMA_ERR:
|
||||
tx_stats(txo)->tx_dma_err++;
|
||||
break;
|
||||
case BE_TX_COMP_ACL_ERR:
|
||||
tx_stats(txo)->tx_spoof_check_err++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void lancer_update_tx_err(struct be_tx_obj *txo, u8 status)
|
||||
{
|
||||
switch (status) {
|
||||
case LANCER_TX_COMP_LSO_ERR:
|
||||
tx_stats(txo)->tx_tso_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_HSW_DROP_MAC_ERR:
|
||||
case LANCER_TX_COMP_HSW_DROP_VLAN_ERR:
|
||||
tx_stats(txo)->tx_spoof_check_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_QINQ_ERR:
|
||||
tx_stats(txo)->tx_qinq_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_PARITY_ERR:
|
||||
tx_stats(txo)->tx_internal_parity_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_DMA_ERR:
|
||||
tx_stats(txo)->tx_dma_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_SGE_ERR:
|
||||
tx_stats(txo)->tx_sge_err++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct be_tx_compl_info *be_tx_compl_get(struct be_adapter *adapter,
|
||||
struct be_tx_obj *txo)
|
||||
{
|
||||
struct be_queue_info *tx_cq = &txo->cq;
|
||||
struct be_tx_compl_info *txcp = &txo->txcp;
|
||||
@@ -2599,6 +2640,24 @@ static struct be_tx_compl_info *be_tx_compl_get(struct be_tx_obj *txo)
|
||||
txcp->status = GET_TX_COMPL_BITS(status, compl);
|
||||
txcp->end_index = GET_TX_COMPL_BITS(wrb_index, compl);
|
||||
|
||||
if (txcp->status) {
|
||||
if (lancer_chip(adapter)) {
|
||||
lancer_update_tx_err(txo, txcp->status);
|
||||
/* Reset the adapter incase of TSO,
|
||||
* SGE or Parity error
|
||||
*/
|
||||
if (txcp->status == LANCER_TX_COMP_LSO_ERR ||
|
||||
txcp->status == LANCER_TX_COMP_PARITY_ERR ||
|
||||
txcp->status == LANCER_TX_COMP_SGE_ERR)
|
||||
be_set_error(adapter, BE_ERROR_TX);
|
||||
} else {
|
||||
be_update_tx_err(txo, txcp->status);
|
||||
}
|
||||
}
|
||||
|
||||
if (be_check_error(adapter, BE_ERROR_TX))
|
||||
return NULL;
|
||||
|
||||
compl->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
|
||||
queue_tail_inc(tx_cq);
|
||||
return txcp;
|
||||
@@ -2741,7 +2800,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
|
||||
cmpl = 0;
|
||||
num_wrbs = 0;
|
||||
txq = &txo->q;
|
||||
while ((txcp = be_tx_compl_get(txo))) {
|
||||
while ((txcp = be_tx_compl_get(adapter, txo))) {
|
||||
num_wrbs +=
|
||||
be_tx_compl_process(adapter, txo,
|
||||
txcp->end_index);
|
||||
@@ -3120,42 +3179,6 @@ loop_continue:
|
||||
return work_done;
|
||||
}
|
||||
|
||||
static inline void be_update_tx_err(struct be_tx_obj *txo, u8 status)
|
||||
{
|
||||
switch (status) {
|
||||
case BE_TX_COMP_HDR_PARSE_ERR:
|
||||
tx_stats(txo)->tx_hdr_parse_err++;
|
||||
break;
|
||||
case BE_TX_COMP_NDMA_ERR:
|
||||
tx_stats(txo)->tx_dma_err++;
|
||||
break;
|
||||
case BE_TX_COMP_ACL_ERR:
|
||||
tx_stats(txo)->tx_spoof_check_err++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void lancer_update_tx_err(struct be_tx_obj *txo, u8 status)
|
||||
{
|
||||
switch (status) {
|
||||
case LANCER_TX_COMP_LSO_ERR:
|
||||
tx_stats(txo)->tx_tso_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_HSW_DROP_MAC_ERR:
|
||||
case LANCER_TX_COMP_HSW_DROP_VLAN_ERR:
|
||||
tx_stats(txo)->tx_spoof_check_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_QINQ_ERR:
|
||||
tx_stats(txo)->tx_qinq_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_PARITY_ERR:
|
||||
tx_stats(txo)->tx_internal_parity_err++;
|
||||
break;
|
||||
case LANCER_TX_COMP_DMA_ERR:
|
||||
tx_stats(txo)->tx_dma_err++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
|
||||
int idx)
|
||||
@@ -3163,16 +3186,9 @@ static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
|
||||
int num_wrbs = 0, work_done = 0;
|
||||
struct be_tx_compl_info *txcp;
|
||||
|
||||
while ((txcp = be_tx_compl_get(txo))) {
|
||||
while ((txcp = be_tx_compl_get(adapter, txo))) {
|
||||
num_wrbs += be_tx_compl_process(adapter, txo, txcp->end_index);
|
||||
work_done++;
|
||||
|
||||
if (txcp->status) {
|
||||
if (lancer_chip(adapter))
|
||||
lancer_update_tx_err(txo, txcp->status);
|
||||
else
|
||||
be_update_tx_err(txo, txcp->status);
|
||||
}
|
||||
}
|
||||
|
||||
if (work_done) {
|
||||
@@ -5104,9 +5120,12 @@ static netdev_features_t be_features_check(struct sk_buff *skb,
|
||||
features &= ~NETIF_F_TSO6;
|
||||
|
||||
/* Lancer cannot handle the packet with MSS less than 256.
|
||||
* Also it can't handle a TSO packet with a single segment
|
||||
* Disable the GSO support in such cases
|
||||
*/
|
||||
if (lancer_chip(adapter) && skb_shinfo(skb)->gso_size < 256)
|
||||
if (lancer_chip(adapter) &&
|
||||
(skb_shinfo(skb)->gso_size < 256 ||
|
||||
skb_shinfo(skb)->gso_segs == 1))
|
||||
features &= ~NETIF_F_GSO_MASK;
|
||||
}
|
||||
|
||||
|
||||
@@ -3286,7 +3286,7 @@ static void handle_vpd_rsp(union ibmvnic_crq *crq,
|
||||
struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
struct device *dev = &adapter->vdev->dev;
|
||||
unsigned char *substr = NULL, *ptr = NULL;
|
||||
unsigned char *substr = NULL;
|
||||
u8 fw_level_len = 0;
|
||||
|
||||
memset(adapter->fw_version, 0, 32);
|
||||
@@ -3306,10 +3306,6 @@ static void handle_vpd_rsp(union ibmvnic_crq *crq,
|
||||
substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
|
||||
if (!substr) {
|
||||
dev_info(dev, "Warning - No FW level has been provided in the VPD buffer by the VIOS Server\n");
|
||||
ptr = strncpy((char *)adapter->fw_version, "N/A",
|
||||
3 * sizeof(char));
|
||||
if (!ptr)
|
||||
dev_err(dev, "Failed to inform that firmware version is unavailable to the adapter\n");
|
||||
goto complete;
|
||||
}
|
||||
|
||||
@@ -3324,16 +3320,14 @@ static void handle_vpd_rsp(union ibmvnic_crq *crq,
|
||||
/* copy firmware version string from vpd into adapter */
|
||||
if ((substr + 3 + fw_level_len) <
|
||||
(adapter->vpd->buff + adapter->vpd->len)) {
|
||||
ptr = strncpy((char *)adapter->fw_version,
|
||||
substr + 3, fw_level_len);
|
||||
|
||||
if (!ptr)
|
||||
dev_err(dev, "Failed to isolate FW level string\n");
|
||||
strncpy((char *)adapter->fw_version, substr + 3, fw_level_len);
|
||||
} else {
|
||||
dev_info(dev, "FW substr extrapolated VPD buff\n");
|
||||
}
|
||||
|
||||
complete:
|
||||
if (adapter->fw_version[0] == '\0')
|
||||
strncpy((char *)adapter->fw_version, "N/A", 3 * sizeof(char));
|
||||
complete(&adapter->fw_done);
|
||||
}
|
||||
|
||||
|
||||
@@ -112,22 +112,22 @@ enum pkt_vec {
|
||||
* @map_elems_in_use: number of elements allocated to offloaded maps
|
||||
*
|
||||
* @adjust_head: adjust head capability
|
||||
* @flags: extra flags for adjust head
|
||||
* @off_min: minimal packet offset within buffer required
|
||||
* @off_max: maximum packet offset within buffer required
|
||||
* @guaranteed_sub: amount of negative adjustment guaranteed possible
|
||||
* @guaranteed_add: amount of positive adjustment guaranteed possible
|
||||
* @adjust_head.flags: extra flags for adjust head
|
||||
* @adjust_head.off_min: minimal packet offset within buffer required
|
||||
* @adjust_head.off_max: maximum packet offset within buffer required
|
||||
* @adjust_head.guaranteed_sub: negative adjustment guaranteed possible
|
||||
* @adjust_head.guaranteed_add: positive adjustment guaranteed possible
|
||||
*
|
||||
* @maps: map capability
|
||||
* @types: supported map types
|
||||
* @max_maps: max number of maps supported
|
||||
* @max_elems: max number of entries in each map
|
||||
* @max_key_sz: max size of map key
|
||||
* @max_val_sz: max size of map value
|
||||
* @max_elem_sz: max size of map entry (key + value)
|
||||
* @maps.types: supported map types
|
||||
* @maps.max_maps: max number of maps supported
|
||||
* @maps.max_elems: max number of entries in each map
|
||||
* @maps.max_key_sz: max size of map key
|
||||
* @maps.max_val_sz: max size of map value
|
||||
* @maps.max_elem_sz: max size of map entry (key + value)
|
||||
*
|
||||
* @helpers: helper addressess for various calls
|
||||
* @map_lookup: map lookup helper address
|
||||
* @helpers.map_lookup: map lookup helper address
|
||||
*/
|
||||
struct nfp_app_bpf {
|
||||
struct nfp_app *app;
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
* @seq: sequence number of the message
|
||||
* @count: number of tunnels report in message
|
||||
* @flags: options part of the request
|
||||
* @ipv4: dest IPv4 address of active route
|
||||
* @egress_port: port the encapsulated packet egressed
|
||||
* @extra: reserved for future use
|
||||
* @tun_info.ipv4: dest IPv4 address of active route
|
||||
* @tun_info.egress_port: port the encapsulated packet egressed
|
||||
* @tun_info.extra: reserved for future use
|
||||
* @tun_info: tunnels that have sent traffic in reported period
|
||||
*/
|
||||
struct nfp_tun_active_tuns {
|
||||
@@ -132,8 +132,8 @@ struct nfp_ipv4_addr_entry {
|
||||
* struct nfp_tun_mac_addr - configure MAC address of tunnel EP on NFP
|
||||
* @reserved: reserved for future use
|
||||
* @count: number of MAC addresses in the message
|
||||
* @index: index of MAC address in the lookup table
|
||||
* @addr: interface MAC address
|
||||
* @addresses.index: index of MAC address in the lookup table
|
||||
* @addresses.addr: interface MAC address
|
||||
* @addresses: series of MACs to offload
|
||||
*/
|
||||
struct nfp_tun_mac_addr {
|
||||
|
||||
@@ -193,7 +193,8 @@ struct nfp_net_tx_desc {
|
||||
|
||||
/**
|
||||
* struct nfp_net_tx_buf - software TX buffer descriptor
|
||||
* @skb: sk_buff associated with this buffer
|
||||
* @skb: normal ring, sk_buff associated with this buffer
|
||||
* @frag: XDP ring, page frag associated with this buffer
|
||||
* @dma_addr: DMA mapping address of the buffer
|
||||
* @fidx: Fragment index (-1 for the head and [0..nr_frags-1] for frags)
|
||||
* @pkt_cnt: Number of packets to be produced out of the skb associated
|
||||
@@ -377,6 +378,9 @@ struct nfp_net_rx_ring {
|
||||
* struct nfp_net_r_vector - Per ring interrupt vector configuration
|
||||
* @nfp_net: Backpointer to nfp_net structure
|
||||
* @napi: NAPI structure for this ring vec
|
||||
* @tasklet: ctrl vNIC, tasklet for servicing the r_vec
|
||||
* @queue: ctrl vNIC, send queue
|
||||
* @lock: ctrl vNIC, r_vec lock protects @queue
|
||||
* @tx_ring: Pointer to TX ring
|
||||
* @rx_ring: Pointer to RX ring
|
||||
* @xdp_ring: Pointer to an extra TX ring for XDP
|
||||
|
||||
@@ -98,28 +98,29 @@ enum nfp_eth_fec {
|
||||
* @max_index: max of @index fields of all @ports
|
||||
* @ports: table of ports
|
||||
*
|
||||
* @eth_index: port index according to legacy ethX numbering
|
||||
* @index: chip-wide first channel index
|
||||
* @nbi: NBI index
|
||||
* @base: first channel index (within NBI)
|
||||
* @lanes: number of channels
|
||||
* @speed: interface speed (in Mbps)
|
||||
* @interface: interface (module) plugged in
|
||||
* @media: media type of the @interface
|
||||
* @fec: forward error correction mode
|
||||
* @aneg: auto negotiation mode
|
||||
* @mac_addr: interface MAC address
|
||||
* @label_port: port id
|
||||
* @label_subport: id of interface within port (for split ports)
|
||||
* @enabled: is enabled?
|
||||
* @tx_enabled: is TX enabled?
|
||||
* @rx_enabled: is RX enabled?
|
||||
* @override_changed: is media reconfig pending?
|
||||
* @ports.eth_index: port index according to legacy ethX numbering
|
||||
* @ports.index: chip-wide first channel index
|
||||
* @ports.nbi: NBI index
|
||||
* @ports.base: first channel index (within NBI)
|
||||
* @ports.lanes: number of channels
|
||||
* @ports.speed: interface speed (in Mbps)
|
||||
* @ports.interface: interface (module) plugged in
|
||||
* @ports.media: media type of the @interface
|
||||
* @ports.fec: forward error correction mode
|
||||
* @ports.aneg: auto negotiation mode
|
||||
* @ports.mac_addr: interface MAC address
|
||||
* @ports.label_port: port id
|
||||
* @ports.label_subport: id of interface within port (for split ports)
|
||||
* @ports.enabled: is enabled?
|
||||
* @ports.tx_enabled: is TX enabled?
|
||||
* @ports.rx_enabled: is RX enabled?
|
||||
* @ports.override_changed: is media reconfig pending?
|
||||
*
|
||||
* @port_type: one of %PORT_* defines for ethtool
|
||||
* @port_lanes: total number of lanes on the port (sum of lanes of all subports)
|
||||
* @is_split: is interface part of a split port
|
||||
* @fec_modes_supported: bitmap of FEC modes supported
|
||||
* @ports.port_type: one of %PORT_* defines for ethtool
|
||||
* @ports.port_lanes: total number of lanes on the port (sum of lanes of all
|
||||
* subports)
|
||||
* @ports.is_split: is interface part of a split port
|
||||
* @ports.fec_modes_supported: bitmap of FEC modes supported
|
||||
*/
|
||||
struct nfp_eth_table {
|
||||
unsigned int count;
|
||||
|
||||
@@ -56,16 +56,17 @@
|
||||
|
||||
/**
|
||||
* struct nfp_resource_entry - Resource table entry
|
||||
* @owner: NFP CPP Lock, interface owner
|
||||
* @key: NFP CPP Lock, posix_crc32(name, 8)
|
||||
* @region: Memory region descriptor
|
||||
* @name: ASCII, zero padded name
|
||||
* @reserved
|
||||
* @cpp_action: CPP Action
|
||||
* @cpp_token: CPP Token
|
||||
* @cpp_target: CPP Target ID
|
||||
* @page_offset: 256-byte page offset into target's CPP address
|
||||
* @page_size: size, in 256-byte pages
|
||||
* @mutex: NFP CPP Lock
|
||||
* @mutex.owner: NFP CPP Lock, interface owner
|
||||
* @mutex.key: NFP CPP Lock, posix_crc32(name, 8)
|
||||
* @region: Memory region descriptor
|
||||
* @region.name: ASCII, zero padded name
|
||||
* @region.reserved: padding
|
||||
* @region.cpp_action: CPP Action
|
||||
* @region.cpp_token: CPP Token
|
||||
* @region.cpp_target: CPP Target ID
|
||||
* @region.page_offset: 256-byte page offset into target's CPP address
|
||||
* @region.page_size: size, in 256-byte pages
|
||||
*/
|
||||
struct nfp_resource_entry {
|
||||
struct nfp_resource_entry_mutex {
|
||||
|
||||
@@ -480,8 +480,7 @@ static int
|
||||
nsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap)
|
||||
{
|
||||
struct nsim_bpf_bound_map *nmap;
|
||||
unsigned int i;
|
||||
int err;
|
||||
int i, err;
|
||||
|
||||
if (WARN_ON(offmap->map.map_type != BPF_MAP_TYPE_ARRAY &&
|
||||
offmap->map.map_type != BPF_MAP_TYPE_HASH))
|
||||
@@ -518,7 +517,7 @@ nsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap)
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
while (--i) {
|
||||
while (--i >= 0) {
|
||||
kfree(nmap->entry[i].key);
|
||||
kfree(nmap->entry[i].value);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@ static int mdiobus_register_gpiod(struct mdio_device *mdiodev)
|
||||
gpiod = fwnode_get_named_gpiod(&mdiodev->dev.of_node->fwnode,
|
||||
"reset-gpios", 0, GPIOD_OUT_LOW,
|
||||
"PHY reset");
|
||||
if (PTR_ERR(gpiod) == -ENOENT)
|
||||
if (PTR_ERR(gpiod) == -ENOENT ||
|
||||
PTR_ERR(gpiod) == -ENOSYS)
|
||||
gpiod = NULL;
|
||||
else if (IS_ERR(gpiod))
|
||||
return PTR_ERR(gpiod);
|
||||
|
||||
Reference in New Issue
Block a user