diff options
96 files changed, 2964 insertions, 645 deletions
diff --git a/Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt b/Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt new file mode 100644 index 000000000000..2aaef567c5be --- /dev/null +++ b/Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt @@ -0,0 +1,23 @@ +* MCR20A IEEE 802.15.4 * + +Required properties: + - compatible: should be "nxp,mcr20a" + - spi-max-frequency: maximal bus speed, should be set to a frequency + lower than 9000000 depends sync or async operation mode + - reg: the chipselect index + - interrupts: the interrupt generated by the device. Non high-level + can occur deadlocks while handling isr. + +Optional properties: + - rst_b-gpio: GPIO spec for the RST_B pin + +Example: + + mcr20a@0 { + compatible = "nxp,mcr20a"; + spi-max-frequency = <9000000>; + reg = <0>; + interrupts = <17 2>; + interrupt-parent = <&gpio>; + rst_b-gpio = <&gpio 27 1> + }; diff --git a/MAINTAINERS b/MAINTAINERS index 93a12af4f180..e0b39004edc0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8592,6 +8592,15 @@ S: Maintained F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531 F: drivers/iio/potentiometer/mcp4531.c +MCR20A IEEE-802.15.4 RADIO DRIVER +M: Xue Liu <liuxuenetmail@gmail.com> +L: linux-wpan@vger.kernel.org +W: https://github.com/xueliu/mcr20a-linux +S: Maintained +F: drivers/net/ieee802154/mcr20a.c +F: drivers/net/ieee802154/mcr20a.h +F: Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt + MEASUREMENT COMPUTING CIO-DAC IIO DRIVER M: William Breathitt Gray <vilhelm.gray@gmail.com> L: linux-iio@vger.kernel.org diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index e66963ca58bd..3ae32d1ddd27 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -4549,6 +4549,7 @@ static struct pernet_operations cma_pernet_operations = { .exit = cma_exit_net, .id = &cma_pernet_id, .size = sizeof(struct cma_pernet), + .async = true, }; static int __init cma_init(void) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d88b78a17440..08b85215c2be 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -149,6 +149,7 @@ config MACVTAP config IPVLAN tristate "IP-VLAN support" depends on INET + depends on IPV6 || !IPV6 depends on NETFILTER select NET_L3_MASTER_DEV ---help--- diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index c669554d70bb..4c19d23dd282 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4791,6 +4791,7 @@ static struct pernet_operations bond_net_ops = { .exit = bond_net_exit, .id = &bond_net_id, .size = sizeof(struct bond_net), + .async = true, }; static int __init bonding_init(void) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index a998c36c5e61..159dc2df878d 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -454,6 +454,16 @@ static void dpaa_set_rx_mode(struct net_device *net_dev) err); } + if (!!(net_dev->flags & IFF_ALLMULTI) != priv->mac_dev->allmulti) { + priv->mac_dev->allmulti = !priv->mac_dev->allmulti; + err = priv->mac_dev->set_allmulti(priv->mac_dev->fman_mac, + priv->mac_dev->allmulti); + if (err < 0) + netif_err(priv, drv, net_dev, + "mac_dev->set_allmulti() = %d\n", + err); + } + err = priv->mac_dev->set_multi(net_dev, priv->mac_dev); if (err < 0) netif_err(priv, drv, net_dev, "mac_dev->set_multi() = %d\n", @@ -1916,8 +1926,10 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, goto csum_failed; } + /* SGT[0] is used by the linear part */ sgt = (struct qm_sg_entry *)(sgt_buf + priv->tx_headroom); - qm_sg_entry_set_len(&sgt[0], skb_headlen(skb)); + frag_len = skb_headlen(skb); + qm_sg_entry_set_len(&sgt[0], frag_len); sgt[0].bpid = FSL_DPAA_BPID_INV; sgt[0].offset = 0; addr = dma_map_single(dev, skb->data, @@ -1930,9 +1942,9 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, qm_sg_entry_set64(&sgt[0], addr); /* populate the rest of SGT entries */ - frag = &skb_shinfo(skb)->frags[0]; - frag_len = frag->size; - for (i = 1; i <= nr_frags; i++, frag++) { + for (i = 0; i < nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + frag_len = frag->size; WARN_ON(!skb_frag_page(frag)); addr = skb_frag_dma_map(dev, frag, 0, frag_len, dma_dir); @@ -1942,15 +1954,16 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, goto sg_map_failed; } - qm_sg_entry_set_len(&sgt[i], frag_len); - sgt[i].bpid = FSL_DPAA_BPID_INV; - sgt[i].offset = 0; + qm_sg_entry_set_len(&sgt[i + 1], frag_len); + sgt[i + 1].bpid = FSL_DPAA_BPID_INV; + sgt[i + 1].offset = 0; /* keep the offset in the address */ - qm_sg_entry_set64(&sgt[i], addr); - frag_len = frag->size; + qm_sg_entry_set64(&sgt[i + 1], addr); } - qm_sg_entry_set_f(&sgt[i - 1], frag_len); + + /* Set the final bit in the last used entry of the SGT */ + qm_sg_entry_set_f(&sgt[nr_frags], frag_len); qm_fd_set_sg(fd, priv->tx_headroom, skb->len); @@ -2052,19 +2065,23 @@ static int dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev) /* MAX_SKB_FRAGS is equal or larger than our dpaa_SGT_MAX_ENTRIES; * make sure we don't feed FMan with more fragments than it supports. */ - if (nonlinear && - likely(skb_shinfo(skb)->nr_frags < DPAA_SGT_MAX_ENTRIES)) { - /* Just create a S/G fd based on the skb */ - err = skb_to_sg_fd(priv, skb, &fd); - percpu_priv->tx_frag_skbuffs++; - } else { + if (unlikely(nonlinear && + (skb_shinfo(skb)->nr_frags >= DPAA_SGT_MAX_ENTRIES))) { /* If the egress skb contains more fragments than we support * we have no choice but to linearize it ourselves. */ - if (unlikely(nonlinear) && __skb_linearize(skb)) + if (__skb_linearize(skb)) goto enomem; - /* Finally, create a contig FD from this skb */ + nonlinear = skb_is_nonlinear(skb); + } + + if (nonlinear) { + /* Just create a S/G fd based on the skb */ + err = skb_to_sg_fd(priv, skb, &fd); + percpu_priv->tx_frag_skbuffs++; + } else { + /* Create a contig FD from this skb */ err = skb_to_contig_fd(priv, skb, &fd, &offset); } if (unlikely(err < 0)) @@ -2201,14 +2218,8 @@ static enum qman_cb_dqrr_result rx_error_dqrr(struct qman_portal *portal, if (dpaa_eth_napi_schedule(percpu_priv, portal)) return qman_cb_dqrr_stop; - if (dpaa_eth_refill_bpools(priv)) - /* Unable to refill the buffer pool due to insufficient - * system memory. Just release the frame back into the pool, - * otherwise we'll soon end up with an empty buffer pool. - */ - dpaa_fd_release(net_dev, &dq->fd); - else - dpaa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); + dpaa_eth_refill_bpools(priv); + dpaa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); return qman_cb_dqrr_consume; } diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c index ea43b4974149..9a581faaa742 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@ -1117,6 +1117,25 @@ int dtsec_add_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr) return 0; } +int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable) +{ + u32 tmp; + struct dtsec_regs __iomem *regs = dtsec->regs; + + if (!is_init_done(dtsec->dtsec_drv_param)) + return -EINVAL; + + tmp = ioread32be(®s->rctrl); + if (enable) + tmp |= RCTRL_MPROM; + else + tmp &= ~RCTRL_MPROM; + + iowrite32be(tmp, ®s->rctrl); + + return 0; +} + int dtsec_del_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr) { struct dtsec_regs __iomem *regs = dtsec->regs; diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.h b/drivers/net/ethernet/freescale/fman/fman_dtsec.h index c4467c072058..1a689adf5a22 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.h +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.h @@ -55,5 +55,6 @@ int dtsec_set_exception(struct fman_mac *dtsec, int dtsec_add_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr); int dtsec_del_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr); int dtsec_get_version(struct fman_mac *dtsec, u32 *mac_version); +int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable); #endif /* __DTSEC_H */ diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index c0296880feba..446a97b792e3 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -350,6 +350,7 @@ struct fman_mac { struct fman_rev_info fm_rev_info; bool basex_if; struct phy_device *pcsphy; + bool allmulti_enabled; }; static void add_addr_in_paddr(struct memac_regs __iomem *regs, u8 *adr, @@ -940,6 +941,29 @@ int memac_add_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr) return 0; } +int memac_set_allmulti(struct fman_mac *memac, bool enable) +{ + u32 entry; + struct memac_regs __iomem *regs = memac->regs; + + if (!is_init_done(memac->memac_drv_param)) + return -EINVAL; + + if (enable) { + for (entry = 0; entry < HASH_TABLE_SIZE; entry++) + iowrite32be(entry | HASH_CTRL_MCAST_EN, + ®s->hashtable_ctrl); + } else { + for (entry = 0; entry < HASH_TABLE_SIZE; entry++) + iowrite32be(entry & ~HASH_CTRL_MCAST_EN, + ®s->hashtable_ctrl); + } + + memac->allmulti_enabled = enable; + + return 0; +} + int memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr) { struct memac_regs __iomem *regs = memac->regs; @@ -963,8 +987,12 @@ int memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr) break; } } - if (list_empty(&memac->multicast_addr_hash->lsts[hash])) - iowrite32be(hash & ~HASH_CTRL_MCAST_EN, ®s->hashtable_ctrl); + + if (!memac->allmulti_enabled) { + if (list_empty(&memac->multicast_addr_hash->lsts[hash])) + iowrite32be(hash & ~HASH_CTRL_MCAST_EN, + ®s->hashtable_ctrl); + } return 0; } diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.h b/drivers/net/ethernet/freescale/fman/fman_memac.h index c4a66469a907..b5a50338ed9a 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.h +++ b/drivers/net/ethernet/freescale/fman/fman_memac.h @@ -57,5 +57,6 @@ int memac_set_exception(struct fman_mac *memac, enum fman_mac_exceptions exception, bool enable); int memac_add_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr); int memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr); +int memac_set_allmulti(struct fman_mac *memac, bool enable); #endif /* __MEMAC_H */ diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.c b/drivers/net/ethernet/freescale/fman/fman_tgec.c index 4b0f3a50b293..284735d4ebe9 100644 --- a/drivers/net/ethernet/freescale/fman/fman_tgec.c +++ b/drivers/net/ethernet/freescale/fman/fman_tgec.c @@ -217,6 +217,7 @@ struct fman_mac { struct tgec_cfg *cfg; void *fm; struct fman_rev_info fm_rev_info; + bool allmulti_enabled; }; static void set_mac_address(struct tgec_regs __iomem *regs, u8 *adr) @@ -564,6 +565,29 @@ int tgec_add_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr) return 0; } +int tgec_set_allmulti(struct fman_mac *tgec, bool enable) +{ + u32 entry; + struct tgec_regs __iomem *regs = tgec->regs; + + if (!is_init_done(tgec->cfg)) + return -EINVAL; + + if (enable) { + for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++) + iowrite32be(entry | TGEC_HASH_MCAST_EN, + ®s->hashtable_ctrl); + } else { + for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++) + iowrite32be(entry & ~TGEC_HASH_MCAST_EN, + ®s->hashtable_ctrl); + } + + tgec->allmulti_enabled = enable; + + return 0; +} + int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr) { struct tgec_regs __iomem *regs = tgec->regs; @@ -591,9 +615,12 @@ int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr) break; } } - if (list_empty(&tgec->multicast_addr_hash->lsts[hash])) - iowrite32be((hash & ~TGEC_HASH_MCAST_EN), - ®s->hashtable_ctrl); + + if (!tgec->allmulti_enabled) { + if (list_empty(&tgec->multicast_addr_hash->lsts[hash])) + iowrite32be((hash & ~TGEC_HASH_MCAST_EN), + ®s->hashtable_ctrl); + } return 0; } diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.h b/drivers/net/ethernet/freescale/fman/fman_tgec.h index 514bba9f47ce..cbbd3b422a98 100644 --- a/drivers/net/ethernet/freescale/fman/fman_tgec.h +++ b/drivers/net/ethernet/freescale/fman/fman_tgec.h @@ -51,5 +51,6 @@ int tgec_set_exception(struct fman_mac *tgec, int tgec_add_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr); int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr); int tgec_get_version(struct fman_mac *tgec, u32 *mac_version); +int tgec_set_allmulti(struct fman_mac *tgec, bool enable); #endif /* __TGEC_H */ diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c index 88c0a0636b44..4829dcd9e077 100644 --- a/drivers/net/ethernet/freescale/fman/mac.c +++ b/drivers/net/ethernet/freescale/fman/mac.c @@ -470,6 +470,7 @@ static void setup_dtsec(struct mac_device *mac_dev) mac_dev->set_tx_pause = dtsec_set_tx_pause_frames; mac_dev->set_rx_pause = dtsec_accept_rx_pause_frames; mac_dev->set_exception = dtsec_set_exception; + mac_dev->set_allmulti = dtsec_set_allmulti; mac_dev->set_multi = set_multi; mac_dev->start = start; mac_dev->stop = stop; @@ -488,6 +489,7 @@ static void setup_tgec(struct mac_device *mac_dev) mac_dev->set_tx_pause = tgec_set_tx_pause_frames; mac_dev->set_rx_pause = tgec_accept_rx_pause_frames; mac_dev->set_exception = tgec_set_exception; + mac_dev->set_allmulti = tgec_set_allmulti; mac_dev->set_multi = set_multi; mac_dev->start = start; mac_dev->stop = stop; @@ -506,6 +508,7 @@ static void setup_memac(struct mac_device *mac_dev) mac_dev->set_tx_pause = memac_set_tx_pause_frames; mac_dev->set_rx_pause = memac_accept_rx_pause_frames; mac_dev->set_exception = memac_set_exception; + mac_dev->set_allmulti = memac_set_allmulti; mac_dev->set_multi = set_multi; mac_dev->start = start; mac_dev->stop = stop; diff --git a/drivers/net/ethernet/freescale/fman/mac.h b/drivers/net/ethernet/freescale/fman/mac.h index eefb3357e304..b520cec120ee 100644 --- a/drivers/net/ethernet/freescale/fman/mac.h +++ b/drivers/net/ethernet/freescale/fman/mac.h @@ -59,6 +59,7 @@ struct mac_device { bool rx_pause_active; bool tx_pause_active; bool promisc; + bool allmulti; int (*init)(struct mac_device *mac_dev); int (*start)(struct mac_device *mac_dev); @@ -66,6 +67,7 @@ struct mac_device { void (*adjust_link)(struct mac_device *mac_dev); int (*set_promisc)(struct fman_mac *mac_dev, bool enable); int (*change_addr)(struct fman_mac *mac_dev, enet_addr_t *enet_addr); + int (*set_allmulti)(struct fman_mac *mac_dev, bool enable); int (*set_multi)(struct net_device *net_dev, struct mac_device *mac_dev); int (*set_rx_pause)(struct fman_mac *mac_dev, bool en); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 221f15803480..89edb9fae6f0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -3059,6 +3059,8 @@ static int ixgbe_set_rxfh(struct net_device *netdev, const u32 *indir, for (i = 0; i < reta_entries; i++) adapter->rss_indir_tbl[i] = indir[i]; + + ixgbe_store_reta(adapter); } /* Fill out the rss hash key */ @@ -3067,8 +3069,6 @@ static int ixgbe_set_rxfh(struct net_device *netdev, const u32 *indir, ixgbe_store_key(adapter); } - ixgbe_store_reta(adapter); - return 0; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index 4242f0213e46..ed4cbe94c355 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -58,7 +58,6 @@ static bool ixgbe_cache_ring_dcb_sriov(struct ixgbe_adapter *adapter) return false; /* start at VMDq register offset for SR-IOV enabled setups */ - pool = 0; reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask); for (i = 0, pool = 0; i < adapter->num_rx_queues; i++, reg_idx++) { /* If we are greater than indices move to next pool */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 0da5aa2c8aba..b032091022a8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7703,7 +7703,8 @@ static void ixgbe_service_task(struct work_struct *work) if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state)) { ixgbe_ptp_overflow_check(adapter); - ixgbe_ptp_rx_hang(adapter); + if (adapter->flags & IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER) + ixgbe_ptp_rx_hang(adapter); ixgbe_ptp_tx_hang(adapter); } diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index 4400e49090b4..e7623fed42da 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -94,6 +94,13 @@ static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { #define IXGBEVF_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN) +static const char ixgbevf_priv_flags_strings[][ETH_GSTRING_LEN] = { +#define IXGBEVF_PRIV_FLAGS_LEGACY_RX BIT(0) + "legacy-rx", +}; + +#define IXGBEVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbevf_priv_flags_strings) + static int ixgbevf_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { @@ -241,6 +248,8 @@ static void ixgbevf_get_drvinfo(struct net_device *netdev, sizeof(drvinfo->version)); strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), sizeof(drvinfo->bus_info)); + + drvinfo->n_priv_flags = IXGBEVF_PRIV_FLAGS_STR_LEN; } static void ixgbevf_get_ringparam(struct net_device *netdev, @@ -392,6 +401,8 @@ static int ixgbevf_get_sset_count(struct net_device *netdev, int stringset) return IXGBEVF_TEST_LEN; case ETH_SS_STATS: return IXGBEVF_STATS_LEN; + case ETH_SS_PRIV_FLAGS: + return IXGBEVF_PRIV_FLAGS_STR_LEN; default: return -EINVAL; } @@ -496,6 +507,10 @@ static void ixgbevf_get_strings(struct net_device *netdev, u32 stringset, p += ETH_GSTRING_LEN; } break; + case ETH_SS_PRIV_FLAGS: + memcpy(data, ixgbevf_priv_flags_strings, + IXGBEVF_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); + break; } } @@ -888,6 +903,37 @@ static int ixgbevf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, return err; } +static u32 ixgbevf_get_priv_flags(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + u32 priv_flags = 0; + + if (adapter->flags & IXGBEVF_FLAGS_LEGACY_RX) + priv_flags |= IXGBEVF_PRIV_FLAGS_LEGACY_RX; + + return priv_flags; +} + +static int ixgbevf_set_priv_flags(struct net_device *netdev, u32 priv_flags) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + unsigned int flags = adapter->flags; + + flags &= ~IXGBEVF_FLAGS_LEGACY_RX; + if (priv_flags & IXGBEVF_PRIV_FLAGS_LEGACY_RX) + flags |= IXGBEVF_FLAGS_LEGACY_RX; + + if (flags != adapter->flags) { + adapter->flags = flags; + + /* reset interface to repopulate queues */ + if (netif_running(netdev)) + ixgbevf_reinit_locked(adapter); + } + + return 0; +} + static const struct ethtool_ops ixgbevf_ethtool_ops = { .get_drvinfo = ixgbevf_get_drvinfo, .get_regs_len = ixgbevf_get_regs_len, @@ -909,6 +955,8 @@ static const struct ethtool_ops ixgbevf_ethtool_ops = { .get_rxfh_key_size = ixgbevf_get_rxfh_key_size, .get_rxfh = ixgbevf_get_rxfh, .get_link_ksettings = ixgbevf_get_link_ksettings, + .get_priv_flags = ixgbevf_get_priv_flags, + .set_priv_flags = ixgbevf_set_priv_flags, }; void ixgbevf_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index f6952425c87d..f65ca156af2d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -89,19 +89,15 @@ struct ixgbevf_rx_queue_stats { }; enum ixgbevf_ring_state_t { + __IXGBEVF_RX_3K_BUFFER, + __IXGBEVF_RX_BUILD_SKB_ENABLED, __IXGBEVF_TX_DETECT_HANG, __IXGBEVF_HANG_CHECK_ARMED, }; -#define check_for_tx_hang(ring) \ - test_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) -#define set_check_for_tx_hang(ring) \ - set_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) -#define clear_check_for_tx_hang(ring) \ - clear_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) - struct ixgbevf_ring { struct ixgbevf_ring *next; + struct ixgbevf_q_vector *q_vector; /* backpointer to q_vector */ struct net_device *netdev; struct device *dev; void *desc; /* descriptor ring memory */ @@ -133,7 +129,7 @@ struct ixgbevf_ring { */ u16 reg_idx; int queue_index; /* needed for multiqueue queue management */ -}; +} ____cacheline_internodealigned_in_smp; /* How many Rx Buffers do we bundle into one write to the hardware ? */ #define IXGBEVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */ @@ -156,12 +152,20 @@ struct ixgbevf_ring { /* Supported Rx Buffer Sizes */ #define IXGBEVF_RXBUFFER_256 256 /* Used for packet split */ #define IXGBEVF_RXBUFFER_2048 2048 +#define IXGBEVF_RXBUFFER_3072 3072 #define IXGBEVF_RX_HDR_SIZE IXGBEVF_RXBUFFER_256 -#define IXGBEVF_RX_BUFSZ IXGBEVF_RXBUFFER_2048 #define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) +#define IXGBEVF_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN) +#if (PAGE_SIZE < 8192) +#define IXGBEVF_MAX_FRAME_BUILD_SKB \ + (SKB_WITH_OVERHEAD(IXGBEVF_RXBUFFER_2048) - IXGBEVF_SKB_PAD) +#else +#define IXGBEVF_MAX_FRAME_BUILD_SKB IXGBEVF_RXBUFFER_2048 +#endif + #define IXGBE_TX_FLAGS_CSUM BIT(0) #define IXGBE_TX_FLAGS_VLAN BIT(1) #define IXGBE_TX_FLAGS_TSO BIT(2) @@ -170,6 +174,50 @@ struct ixgbevf_ring { #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 +#define ring_uses_large_buffer(ring) \ + test_bit(__IXGBEVF_RX_3K_BUFFER, &(ring)->state) +#define set_ring_uses_large_buffer(ring) \ + set_bit(__IXGBEVF_RX_3K_BUFFER, &(ring)->state) +#define clear_ring_uses_large_buffer(ring) \ + clear_bit(__IXGBEVF_RX_3K_BUFFER, &(ring)->state) + +#define ring_uses_build_skb(ring) \ + test_bit(__IXGBEVF_RX_BUILD_SKB_ENABLED, &(ring)->state) +#define set_ring_build_skb_enabled(ring) \ + set_bit(__IXGBEVF_RX_BUILD_SKB_ENABLED, &(ring)->state) +#define clear_ring_build_skb_enabled(ring) \ + clear_bit(__IXGBEVF_RX_BUILD_SKB_ENABLED, &(ring)->state) + +static inline unsigned int ixgbevf_rx_bufsz(struct ixgbevf_ring *ring) +{ +#if (PAGE_SIZE < 8192) + if (ring_uses_large_buffer(ring)) + return IXGBEVF_RXBUFFER_3072; + + if (ring_uses_build_skb(ring)) + return IXGBEVF_MAX_FRAME_BUILD_SKB; +#endif + return IXGBEVF_RXBUFFER_2048; +} + +static inline unsigned int ixgbevf_rx_pg_order(struct ixgbevf_ring *ring) +{ +#if (PAGE_SIZE < 8192) + if (ring_uses_large_buffer(ring)) + return 1; +#endif + return 0; +} + +#define ixgbevf_rx_pg_size(_ring) (PAGE_SIZE << ixgbevf_rx_pg_order(_ring)) + +#define check_for_tx_hang(ring) \ + test_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) +#define set_check_for_tx_hang(ring) \ + set_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) +#define clear_check_for_tx_hang(ring) \ + clear_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) + struct ixgbevf_ring_container { struct ixgbevf_ring *ring; /* pointer to linked list of rings */ unsigned int total_bytes; /* total bytes processed this int */ @@ -194,7 +242,11 @@ struct ixgbevf_q_vector { u16 itr; /* Interrupt throttle rate written to EITR */ struct napi_struct napi; struct ixgbevf_ring_container rx, tx; + struct rcu_head rcu; /* to avoid race with update stats on free */ char name[IFNAMSIZ + 9]; + + /* for dynamic allocation of rings associated with this q_vector */ + struct ixgbevf_ring ring[0] ____cacheline_internodealigned_in_smp; #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int state; #define IXGBEVF_QV_STATE_IDLE 0 @@ -331,6 +383,8 @@ struct ixgbevf_adapter { u32 *rss_key; u8 rss_indir_tbl[IXGBEVF_X550_VFRETA_SIZE]; + u32 flags; +#define IXGBEVF_FLAGS_LEGACY_RX BIT(1) }; enum ixbgevf_state_t { diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 9b3d43d28106..f37307131eb6 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -130,6 +130,9 @@ static void ixgbevf_service_event_complete(struct ixgbevf_adapter *adapter) static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter); static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector); static void ixgbevf_free_all_rx_resources(struct ixgbevf_adapter *adapter); +static bool ixgbevf_can_reuse_rx_page(struct ixgbevf_rx_buffer *rx_buffer); +static void ixgbevf_reuse_rx_page(struct ixgbevf_ring *rx_ring, + struct ixgbevf_rx_buffer *old_buff); static void ixgbevf_remove_adapter(struct ixgbe_hw *hw) { @@ -527,6 +530,49 @@ static void ixgbevf_process_skb_fields(struct ixgbevf_ring *rx_ring, skb->protocol = eth_type_trans(skb, rx_ring->netdev); } +static +struct ixgbevf_rx_buffer *ixgbevf_get_rx_buffer(struct ixgbevf_ring *rx_ring, + const unsigned int size) +{ + struct ixgbevf_rx_buffer *rx_buffer; + + rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; + prefetchw(rx_buffer->page); + + /* we are reusing so sync this buffer for CPU use */ + dma_sync_single_range_for_cpu(rx_ring->dev, + rx_buffer->dma, + rx_buffer->page_offset, + size, + DMA_FROM_DEVICE); + + rx_buffer->pagecnt_bias--; + + return rx_buffer; +} + +static void ixgbevf_put_rx_buffer(struct ixgbevf_ring *rx_ring, + struct ixgbevf_rx_buffer *rx_buffer) +{ + if (ixgbevf_can_reuse_rx_page(rx_buffer)) { + /* hand second half of page back to the ring */ + ixgbevf_reuse_rx_page(rx_ring, rx_buffer); + } else { + /* We are not reusing the buffer so unmap it and free + * any references we are holding to it + */ + dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, + ixgbevf_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, + IXGBEVF_RX_DMA_ATTR); + __page_frag_cache_drain(rx_buffer->page, + rx_buffer->pagecnt_bias); + } + + /* clear contents of rx_buffer */ + rx_buffer->page = NULL; +} + /** * ixgbevf_is_non_eop - process handling of non-EOP buffers * @rx_ring: Rx ring being processed @@ -554,32 +600,38 @@ static bool ixgbevf_is_non_eop(struct ixgbevf_ring *rx_ring, return true; } +static inline unsigned int ixgbevf_rx_offset(struct ixgbevf_ring *rx_ring) +{ + return ring_uses_build_skb(rx_ring) ? IXGBEVF_SKB_PAD : 0; +} + static bool ixgbevf_alloc_mapped_page(struct ixgbevf_ring *rx_ring, struct ixgbevf_rx_buffer *bi) { struct page *page = bi->page; - dma_addr_t dma = bi->dma; + dma_addr_t dma; /* since we are recycling buffers we should seldom need to alloc */ if (likely(page)) return true; /* alloc new page for storage */ - page = dev_alloc_page(); + page = dev_alloc_pages(ixgbevf_rx_pg_order(rx_ring)); if (unlikely(!page)) { rx_ring->rx_stats.alloc_rx_page_failed++; return false; } /* map page for use */ - dma = dma_map_page_attrs(rx_ring->dev, page, 0, PAGE_SIZE, + dma = dma_map_page_attrs(rx_ring->dev, page, 0, + ixgbevf_rx_pg_size(rx_ring), DMA_FROM_DEVICE, IXGBEVF_RX_DMA_ATTR); /* if mapping failed free memory back to system since * there isn't much point in holding memory we can't use */ if (dma_mapping_error(rx_ring->dev, dma)) { - __free_page(page); + __free_pages(page, ixgbevf_rx_pg_order(rx_ring)); rx_ring->rx_stats.alloc_rx_page_failed++; return false; @@ -587,7 +639,7 @@ static bool ixgbevf_alloc_mapped_page(struct ixgbevf_ring *rx_ring, bi->dma = dma; bi->page = page; - bi->page_offset = 0; + bi->page_offset = ixgbevf_rx_offset(rx_ring); bi->pagecnt_bias = 1; rx_ring->rx_stats.alloc_rx_page++; @@ -621,7 +673,7 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_ring *rx_ring, /* sync the buffer for use by the device */ dma_sync_single_range_for_device(rx_ring->dev, bi->dma, bi->page_offset, - IXGBEVF_RX_BUFSZ, + ixgbevf_rx_bufsz(rx_ring), DMA_FROM_DEVICE); /* Refresh the desc even if pkt_addr didn't change @@ -734,11 +786,10 @@ static inline bool ixgbevf_page_is_reserved(struct page *page) return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page); } -static bool ixgbevf_can_reuse_rx_page(struct ixgbevf_rx_buffer *rx_buffer, - struct page *page, - const unsigned int truesize) +static bool ixgbevf_can_reuse_rx_page(struct ixgbevf_rx_buffer *rx_buffer) { - unsigned int pagecnt_bias = rx_buffer->pagecnt_bias--; + unsigned int pagecnt_bias = rx_buffer->pagecnt_bias; + struct page *page = rx_buffer->page; /* avoid re-using remote pages */ if (unlikely(ixgbevf_page_is_reserved(page))) @@ -746,17 +797,13 @@ static bool ixgbevf_can_reuse_rx_page(struct ixgbevf_rx_buffer *rx_buffer, #if (PAGE_SIZE < 8192) /* if we are only owner of page we can reuse it */ - if (unlikely(page_ref_count(page) != pagecnt_bias)) + if (unlikely((page_ref_count(page) - pagecnt_bias) > 1)) return false; - - /* flip page offset to other buffer */ - rx_buffer->page_offset ^= IXGBEVF_RX_BUFSZ; - #else - /* move offset up to the next cache line */ - rx_buffer->page_offset += truesize; +#define IXGBEVF_LAST_OFFSET \ + (SKB_WITH_OVERHEAD(PAGE_SIZE) - IXGBEVF_RXBUFFER_2048) - if (rx_buffer->page_offset > (PAGE_SIZE - IXGBEVF_RX_BUFSZ)) + if (rx_buffer->page_offset > IXGBEVF_LAST_OFFSET) return false; #endif @@ -765,7 +812,7 @@ static bool ixgbevf_can_reuse_rx_page(struct ixgbevf_rx_buffer *rx_buffer, * the pagecnt_bias and page count so that we fully restock the * number of references the driver holds. */ - if (unlikely(pagecnt_bias == 1)) { + if (unlikely(!pagecnt_bias)) { page_ref_add(page, USHRT_MAX); rx_buffer->pagecnt_bias = USHRT_MAX; } @@ -777,127 +824,81 @@ static bool ixgbevf_can_reuse_rx_page(struct ixgbevf_rx_buffer *rx_buffer, * ixgbevf_add_rx_frag - Add contents of Rx buffer to sk_buff * @rx_ring: rx descriptor ring to transact packets on * @rx_buffer: buffer containing page to add - * @rx_desc: descriptor containing length of buffer written by hardware * @skb: sk_buff to place the data into + * @size: size of buffer to be added * * This function will add the data contained in rx_buffer->page to the skb. - * This is done either through a direct copy if the data in the buffer is - * less than the skb header size, otherwise it will just attach the page as - * a frag to the skb. - * - * The function will then update the page offset if necessary and return - * true if the buffer can be reused by the adapter. **/ -static bool ixgbevf_add_rx_frag(struct ixgbevf_ring *rx_ring, +static void ixgbevf_add_rx_frag(struct ixgbevf_ring *rx_ring, struct ixgbevf_rx_buffer *rx_buffer, - u16 size, - union ixgbe_adv_rx_desc *rx_desc, - struct sk_buff *skb) + struct sk_buff *skb, + unsigned int size) { - struct page *page = rx_buffer->page; - unsigned char *va = page_address(page) + rx_buffer->page_offset; #if (PAGE_SIZE < 8192) - unsigned int truesize = IXGBEVF_RX_BUFSZ; + unsigned int truesize = ixgbevf_rx_pg_size(rx_ring) / 2; #else - unsigned int truesize = ALIGN(size, L1_CACHE_BYTES); + unsigned int truesize = ring_uses_build_skb(rx_ring) ? + SKB_DATA_ALIGN(IXGBEVF_SKB_PAD + size) : + SKB_DATA_ALIGN(size); +#endif + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page, + rx_buffer->page_offset, size, truesize); +#if (PAGE_SIZE < 8192) + rx_buffer->page_offset ^= truesize; +#else + rx_buffer->page_offset += truesize; #endif - unsigned int pull_len; - - if (unlikely(skb_is_nonlinear(skb))) - goto add_tail_frag; - - if (likely(size <= IXGBEVF_RX_HDR_SIZE)) { - memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); - - /* page is not reserved, we can reuse buffer as is */ - if (likely(!ixgbevf_page_is_reserved(page))) - return true; - - /* this page cannot be reused so discard it */ - return false; - } - - /* we need the header to contain the greater of either ETH_HLEN or - * 60 bytes if the skb->len is less than 60 for skb_pad. - */ - pull_len = eth_get_headlen(va, IXGBEVF_RX_HDR_SIZE); - - /* align pull length to size of long to optimize memcpy performance */ - memcpy(__skb_put(skb, pull_len), va, ALIGN(pull_len, sizeof(long))); - - /* update all of the pointers */ - va += pull_len; - size -= pull_len; - -add_tail_frag: - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - (unsigned long)va & ~PAGE_MASK, size, truesize); - - return ixgbevf_can_reuse_rx_page(rx_buffer, page, truesize); } -static struct sk_buff *ixgbevf_fetch_rx_buffer(struct ixgbevf_ring *rx_ring, - union ixgbe_adv_rx_desc *rx_desc, - struct sk_buff *skb) +static +struct sk_buff *ixgbevf_construct_skb(struct ixgbevf_ring *rx_ring, + struct ixgbevf_rx_buffer *rx_buffer, + union ixgbe_adv_rx_desc *rx_desc, + unsigned int size) { - struct ixgbevf_rx_buffer *rx_buffer; - struct page *page; - u16 size = le16_to_cpu(rx_desc->wb.upper.length); - - rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; - page = rx_buffer->page; - prefetchw(page); - - /* we are reusing so sync this buffer for CPU use */ - dma_sync_single_range_for_cpu(rx_ring->dev, - rx_buffer->dma, - rx_buffer->page_offset, - size, - DMA_FROM_DEVICE); - - if (likely(!skb)) { - void *page_addr = page_address(page) + - rx_buffer->page_offset; + void *va = page_address(rx_buffer->page) + rx_buffer->page_offset; +#if (PAGE_SIZE < 8192) + unsigned int truesize = ixgbevf_rx_pg_size(rx_ring) / 2; +#else + unsigned int truesize = SKB_DATA_ALIGN(size); +#endif + unsigned int headlen; + struct sk_buff *skb; - /* prefetch first cache line of first page */ - prefetch(page_addr); + /* prefetch first cache line of first page */ + prefetch(va); #if L1_CACHE_BYTES < 128 - prefetch(page_addr + L1_CACHE_BYTES); + prefetch(va + L1_CACHE_BYTES); #endif - /* allocate a skb to store the frags */ - skb = netdev_alloc_skb_ip_align(rx_ring->netdev, - IXGBEVF_RX_HDR_SIZE); - if (unlikely(!skb)) { - rx_ring->rx_stats.alloc_rx_buff_failed++; - return NULL; - } + /* allocate a skb to store the frags */ + skb = napi_alloc_skb(&rx_ring->q_vector->napi, IXGBEVF_RX_HDR_SIZE); + if (unlikely(!skb)) + return NULL; - /* we will be copying header into skb->data in - * pskb_may_pull so it is in our interest to prefetch - * it now to avoid a possible cache miss - */ - prefetchw(skb->data); - } + /* Determine available headroom for copy */ + headlen = size; + if (headlen > IXGBEVF_RX_HDR_SIZE) + headlen = eth_get_headlen(va, IXGBEVF_RX_HDR_SIZE); - /* pull page into skb */ - if (ixgbevf_add_rx_frag(rx_ring, rx_buffer, size, rx_desc, skb)) { - /* hand second half of page back to the ring */ - ixgbevf_reuse_rx_page(rx_ring, rx_buffer); + /* align pull length to size of long to optimize memcpy performance */ + memcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long))); + + /* update all of the pointers */ + size -= headlen; + if (size) { + skb_add_rx_frag(skb, 0, rx_buffer->page, + (va + headlen) - page_address(rx_buffer->page), + size, truesize); +#if (PAGE_SIZE < 8192) + rx_buffer->page_offset ^= truesize; +#else + rx_buffer->page_offset += truesize; +#endif } else { - /* We are not reusing the buffer so unmap it and free - * any references we are holding to it - */ - dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, - PAGE_SIZE, DMA_FROM_DEVICE, - IXGBEVF_RX_DMA_ATTR); - __page_frag_cache_drain(page, rx_buffer->pagecnt_bias); + rx_buffer->pagecnt_bias++; } - /* clear contents of buffer_info */ - rx_buffer->dma = 0; - rx_buffer->page = NULL; - return skb; } @@ -909,6 +910,44 @@ static inline void ixgbevf_irq_enable_queues(struct ixgbevf_adapter *adapter, IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, qmask); } +static struct sk_buff *ixgbevf_build_skb(struct ixgbevf_ring *rx_ring, + struct ixgbevf_rx_buffer *rx_buffer, + union ixgbe_adv_rx_desc *rx_desc, + unsigned int size) +{ + void *va = page_address(rx_buffer->page) + rx_buffer->page_offset; +#if (PAGE_SIZE < 8192) + unsigned int truesize = ixgbevf_rx_pg_size(rx_ring) / 2; +#else + unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + + SKB_DATA_ALIGN(IXGBEVF_SKB_PAD + size); +#endif + struct sk_buff *skb; + + /* prefetch first cache line of first page */ + prefetch(va); +#if L1_CACHE_BYTES < 128 + prefetch(va + L1_CACHE_BYTES); +#endif + + /* build an skb to around the page buffer */ + skb = build_skb(va - IXGBEVF_SKB_PAD, truesize); + if (unlikely(!skb)) + return NULL; + + /* update pointers within the skb to store the data */ + skb_reserve(skb, IXGBEVF_SKB_PAD); + __skb_put(skb, size); + + /* update buffer offset */ +#if (PAGE_SIZE < 8192) + rx_buffer->page_offset ^= truesize; +#else + rx_buffer->page_offset += truesize; +#endif + + return skb; +} static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, struct ixgbevf_ring *rx_ring, int budget) @@ -919,6 +958,8 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, while (likely(total_rx_packets < budget)) { union ixgbe_adv_rx_desc *rx_desc; + struct ixgbevf_rx_buffer *rx_buffer; + unsigned int size; /* return some buffers to hardware, one at a time is too slow */ if (cleaned_count >= IXGBEVF_RX_BUFFER_WRITE) { @@ -927,8 +968,8 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, } rx_desc = IXGBEVF_RX_DESC(rx_ring, rx_ring->next_to_clean); - - if (!rx_desc->wb.upper.length) + size = le16_to_cpu(rx_desc->wb.upper.length); + if (!size) break; /* This memory barrier is needed to keep us from reading @@ -937,15 +978,26 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, */ rmb(); + rx_buffer = ixgbevf_get_rx_buffer(rx_ring, size); + /* retrieve a buffer from the ring */ - skb = ixgbevf_fetch_rx_buffer(rx_ring, rx_desc, skb); + if (skb) + ixgbevf_add_rx_frag(rx_ring, rx_buffer, skb, size); + else if (ring_uses_build_skb(rx_ring)) + skb = ixgbevf_build_skb(rx_ring, rx_buffer, + rx_desc, size); + else + skb = ixgbevf_construct_skb(rx_ring, rx_buffer, + rx_desc, size); /* exit if we failed to retrieve a buffer */ if (!skb) { rx_ring->rx_stats.alloc_rx_buff_failed++; + rx_buffer->pagecnt_bias++; break; } + ixgbevf_put_rx_buffer(rx_ring, rx_buffer); cleaned_count++; /* fetch next buffer in frame if non-eop */ @@ -1260,85 +1312,6 @@ static irqreturn_t ixgbevf_msix_clean_rings(int irq, void *data) return IRQ_HANDLED; } -static inline void map_vector_to_rxq(struct ixgbevf_adapter *a, int v_idx, - int r_idx) -{ - struct ixgbevf_q_vector *q_vector = a->q_vector[v_idx]; - - a->rx_ring[r_idx]->next = q_vector->rx.ring; - q_vector->rx.ring = a->rx_ring[r_idx]; - q_vector->rx.count++; -} - -static inline void map_vector_to_txq(struct ixgbevf_adapter *a, int v_idx, - int t_idx) -{ - struct ixgbevf_q_vector *q_vector = a->q_vector[v_idx]; - - a->tx_ring[t_idx]->next = q_vector->tx.ring; - q_vector->tx.ring = a->tx_ring[t_idx]; - q_vector->tx.count++; -} - -/** - * ixgbevf_map_rings_to_vectors - Maps descriptor rings to vectors - * @adapter: board private structure to initialize - * - * This function maps descriptor rings to the queue-specific vectors - * we were allotted through the MSI-X enabling code. Ideally, we'd have - * one vector per ring/queue, but on a constrained vector budget, we - * group the rings as "efficiently" as possible. You would add new - * mapping configurations in here. - **/ -static int ixgbevf_map_rings_to_vectors(struct ixgbevf_adapter *adapter) -{ - int q_vectors; - int v_start = 0; - int rxr_idx = 0, txr_idx = 0; - int rxr_remaining = adapter->num_rx_queues; - int txr_remaining = adapter->num_tx_queues; - int i, j; - int rqpv, tqpv; - - q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; - - /* The ideal configuration... - * We have enough vectors to map one per queue. - */ - if (q_vectors == adapter->num_rx_queues + adapter->num_tx_queues) { - for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++) - map_vector_to_rxq(adapter, v_start, rxr_idx); - - for (; txr_idx < txr_remaining; v_start++, txr_idx++) - map_vector_to_txq(adapter, v_start, txr_idx); - return 0; - } - - /* If we don't have enough vectors for a 1-to-1 - * mapping, we'll have to group them so there are - * multiple queues per vector. - */ - /* Re-adjusting *qpv takes care of the remainder. */ - for (i = v_start; i < q_vectors; i++) { - rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - i); - for (j = 0; j < rqpv; j++) { - map_vector_to_rxq(adapter, i, rxr_idx); - rxr_idx++; - rxr_remaining--; - } - } - for (i = v_start; i < q_vectors; i++) { - tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - i); - for (j = 0; j < tqpv; j++) { - map_vector_to_txq(adapter, i, txr_idx); - txr_idx++; - txr_remaining--; - } - } - - return 0; -} - /** * ixgbevf_request_msix_irqs - Initialize MSI-X interrupts * @adapter: board private structure @@ -1411,20 +1384,6 @@ free_queue_irqs: return err; } -static inline void ixgbevf_reset_q_vectors(struct ixgbevf_adapter *adapter) -{ - int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; - - for (i = 0; i < q_vectors; i++) { - struct ixgbevf_q_vector *q_vector = adapter->q_vector[i]; - - q_vector->rx.ring = NULL; - q_vector->tx.ring = NULL; - q_vector->rx.count = 0; - q_vector->tx.count = 0; - } -} - /** * ixgbevf_request_irq - initialize interrupts * @adapter: board private structure @@ -1464,8 +1423,6 @@ static void ixgbevf_free_irq(struct ixgbevf_adapter *adapter) free_irq(adapter->msix_entries[i].vector, adapter->q_vector[i]); } - - ixgbevf_reset_q_vectors(adapter); } /** @@ -1587,7 +1544,8 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 -static void ixgbevf_configure_srrctl(struct ixgbevf_adapter *adapter, int index) +static void ixgbevf_configure_srrctl(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *ring, int index) { struct ixgbe_hw *hw = &adapter->hw; u32 srrctl; @@ -1595,7 +1553,10 @@ static void ixgbevf_configure_srrctl(struct ixgbevf_adapter *adapter, int index) srrctl = IXGBE_SRRCTL_DROP_EN; srrctl |= IXGBEVF_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT; - srrctl |= IXGBEVF_RX_BUFSZ >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + if (ring_uses_large_buffer(ring)) + srrctl |= IXGBEVF_RXBUFFER_3072 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + else + srrctl |= IXGBEVF_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(index), srrctl); @@ -1767,10 +1728,21 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, ring->next_to_use = 0; ring->next_to_alloc = 0; - ixgbevf_configure_srrctl(adapter, reg_idx); + ixgbevf_configure_srrctl(adapter, ring, reg_idx); + + /* RXDCTL.RLPML does not work on 82599 */ + if (adapter->hw.mac.type != ixgbe_mac_82599_vf) { + rxdctl &= ~(IXGBE_RXDCTL_RLPMLMASK | + IXGBE_RXDCTL_RLPML_EN); - /* allow any size packet since we can handle overflow */ - rxdctl &= ~IXGBE_RXDCTL_RLPML_EN; +#if (PAGE_SIZE < 8192) + /* Limit the maximum frame size so we don't overrun the skb */ + if (ring_uses_build_skb(ring) && + !ring_uses_large_buffer(ring)) + rxdctl |= IXGBEVF_MAX_FRAME_BUILD_SKB | + IXGBE_RXDCTL_RLPML_EN; +#endif + } rxdctl |= IXGBE_RXDCTL_ENABLE | IXGBE_RXDCTL_VME; IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); @@ -1779,6 +1751,29 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); } +static void ixgbevf_set_rx_buffer_len(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *rx_ring) +{ + struct net_device *netdev = adapter->netdev; + unsigned int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + + /* set build_skb and buffer size flags */ + clear_ring_build_skb_enabled(rx_ring); + clear_ring_uses_large_buffer(rx_ring); + + if (adapter->flags & IXGBEVF_FLAGS_LEGACY_RX) + return; + + set_ring_build_skb_enabled(rx_ring); + +#if (PAGE_SIZE < 8192) + if (max_frame <= IXGBEVF_MAX_FRAME_BUILD_SKB) + return; + + set_ring_uses_large_buffer(rx_ring); +#endif +} + /** * ixgbevf_configure_rx - Configure 82599 VF Receive Unit after Reset * @adapter: board private structure @@ -1806,8 +1801,12 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter) /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ - for (i = 0; i < adapter->num_rx_queues; i++) - ixgbevf_configure_rx_ring(adapter, adapter->rx_ring[i]); + for (i = 0; i < adapter->num_rx_queues; i++) { + struct ixgbevf_ring *rx_ring = adapter->rx_ring[i]; + + ixgbevf_set_rx_buffer_len(adapter, rx_ring); + ixgbevf_configure_rx_ring(adapter, rx_ring); + } } static int ixgbevf_vlan_rx_add_vid(struct net_device *netdev, @@ -2136,13 +2135,13 @@ static void ixgbevf_clean_rx_ring(struct ixgbevf_ring *rx_ring) dma_sync_single_range_for_cpu(rx_ring->dev, rx_buffer->dma, rx_buffer->page_offset, - IXGBEVF_RX_BUFSZ, + ixgbevf_rx_bufsz(rx_ring), DMA_FROM_DEVICE); /* free resources associated with mapping */ dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, - PAGE_SIZE, + ixgbevf_rx_pg_size(rx_ring), DMA_FROM_DEVICE, IXGBEVF_RX_DMA_ATTR); @@ -2405,105 +2404,171 @@ static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter) } /** - * ixgbevf_alloc_queues - Allocate memory for all rings + * ixgbevf_set_interrupt_capability - set MSI-X or FAIL if not supported + * @adapter: board private structure to initialize + * + * Attempt to configure the interrupts using the best available + * capabilities of the hardware and the kernel. + **/ +static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter) +{ + int vector, v_budget; + + /* It's easy to be greedy for MSI-X vectors, but it really + * doesn't do us much good if we have a lot more vectors + * than CPU's. So let's be conservative and only ask for + * (roughly) the same number of vectors as there are CPU's. + * The default is to use pairs of vectors. + */ + v_budget = max(adapter->num_rx_queues, adapter->num_tx_queues); + v_budget = min_t(int, v_budget, num_online_cpus()); + v_budget += NON_Q_VECTORS; + + adapter->msix_entries = kcalloc(v_budget, + sizeof(struct msix_entry), GFP_KERNEL); + if (!adapter->msix_entries) + return -ENOMEM; + + for (vector = 0; vector < v_budget; vector++) + adapter->msix_entries[vector].entry = vector; + + /* A failure in MSI-X entry allocation isn't fatal, but the VF driver + * does not support any other modes, so we will simply fail here. Note + * that we clean up the msix_entries pointer else-where. + */ + return ixgbevf_acquire_msix_vectors(adapter, v_budget); +} + +static void ixgbevf_add_ring(struct ixgbevf_ring *ring, + struct ixgbevf_ring_container *head) +{ + ring->next = head->ring; + head->ring = ring; + head->count++; +} + +/** + * ixgbevf_alloc_q_vector - Allocate memory for a single interrupt vector * @adapter: board private structure to initialize + * @v_idx: index of vector in adapter struct + * @txr_count: number of Tx rings for q vector + * @txr_idx: index of first Tx ring to assign + * @rxr_count: number of Rx rings for q vector + * @rxr_idx: index of first Rx ring to assign * - * We allocate one ring per queue at run-time since we don't know the - * number of queues at compile-time. The polling_netdev array is - * intended for Multiqueue, but should work fine with a single queue. + * We allocate one q_vector. If allocation fails we return -ENOMEM. **/ -static int ixgbevf_alloc_queues(struct ixgbevf_adapter *adapter) +static int ixgbevf_alloc_q_vector(struct ixgbevf_adapter *adapter, int v_idx, + int txr_count, int txr_idx, + int rxr_count, int rxr_idx) { + struct ixgbevf_q_vector *q_vector; struct ixgbevf_ring *ring; - int rx = 0, tx = 0; + int ring_count, size; + + ring_count = txr_count + rxr_count; + size = sizeof(*q_vector) + (sizeof(*ring) * ring_count); + + /* allocate q_vector and rings */ + q_vector = kzalloc(size, GFP_KERNEL); + if (!q_vector) + return -ENOMEM; + + /* initialize NAPI */ + netif_napi_add(adapter->netdev, &q_vector->napi, ixgbevf_poll, 64); + + /* tie q_vector and adapter together */ + adapter->q_vector[v_idx] = q_vector; + q_vector->adapter = adapter; + q_vector->v_idx = v_idx; - for (; tx < adapter->num_tx_queues; tx++) { - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (!ring) - goto err_allocation; + /* initialize pointer to rings */ + ring = q_vector->ring; + while (txr_count) { + /* assign generic ring traits */ ring->dev = &adapter->pdev->dev; ring->netdev = adapter->netdev; + + /* configure backlink on ring */ + ring->q_vector = q_vector; + + /* update q_vector Tx values */ + ixgbevf_add_ring(ring, &q_vector->tx); + + /* apply Tx specific ring traits */ ring->count = adapter->tx_ring_count; - ring->queue_index = tx; - ring->reg_idx = tx; + ring->queue_index = txr_idx; + ring->reg_idx = txr_idx; - adapter->tx_ring[tx] = ring; - } + /* assign ring to adapter */ + adapter->tx_ring[txr_idx] = ring; + + /* update count and index */ + txr_count--; + txr_idx++; - for (; rx < adapter->num_rx_queues; rx++) { - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (!ring) - goto err_allocation; + /* push pointer to next ring */ + ring++; + } + while (rxr_count) { + /* assign generic ring traits */ ring->dev = &adapter->pdev->dev; ring->netdev = adapter->netdev; + /* configure backlink on ring */ + ring->q_vector = q_vector; + + /* update q_vector Rx values */ + ixgbevf_add_ring(ring, &q_vector->rx); + + /* apply Rx specific ring traits */ ring->count = adapter->rx_ring_count; - ring->queue_index = rx; - ring->reg_idx = rx; + ring->queue_index = rxr_idx; + ring->reg_idx = rxr_idx; - adapter->rx_ring[rx] = ring; - } + /* assign ring to adapter */ + adapter->rx_ring[rxr_idx] = ring; - return 0; + /* update count and index */ + rxr_count--; + rxr_idx++; -err_allocation: - while (tx) { - kfree(adapter->tx_ring[--tx]); - adapter->tx_ring[tx] = NULL; + /* push pointer to next ring */ + ring++; } - while (rx) { - kfree(adapter->rx_ring[--rx]); - adapter->rx_ring[rx] = NULL; - } - return -ENOMEM; + return 0; } /** - * ixgbevf_set_interrupt_capability - set MSI-X or FAIL if not supported + * ixgbevf_free_q_vector - Free memory allocated for specific interrupt vector * @adapter: board private structure to initialize + * @v_idx: index of vector in adapter struct * - * Attempt to configure the interrupts using the best available - * capabilities of the hardware and the kernel. + * This function frees the memory allocated to the q_vector. In addition if + * NAPI is enabled it will delete any references to the NAPI struct prior + * to freeing the q_vector. **/ -static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter) +static void ixgbevf_free_q_vector(struct ixgbevf_adapter *adapter, int v_idx) { - struct net_device *netdev = adapter->netdev; - int err; - int vector, v_budget; - - /* It's easy to be greedy for MSI-X vectors, but it really - * doesn't do us much good if we have a lot more vectors - * than CPU's. So let's be conservative and only ask for - * (roughly) the same number of vectors as there are CPU's. - * The default is to use pairs of vectors. - */ - v_budget = max(adapter->num_rx_queues, adapter->num_tx_queues); - v_budget = min_t(int, v_budget, num_online_cpus()); - v_budget += NON_Q_VECTORS; - - /* A failure in MSI-X entry allocation isn't fatal, but it does - * mean we disable MSI-X capabilities of the adapter. - */ - adapter->msix_entries = kcalloc(v_budget, - sizeof(struct msix_entry), GFP_KERNEL); - if (!adapter->msix_entries) - return -ENOMEM; + struct ixgbevf_q_vector *q_vector = adapter->q_vector[v_idx]; + struct ixgbevf_ring *ring; - for (vector = 0; vector < v_budget; vector++) - adapter->msix_entries[vector].entry = vector; + ixgbevf_for_each_ring(ring, q_vector->tx) + adapter->tx_ring[ring->queue_index] = NULL; - err = ixgbevf_acquire_msix_vectors(adapter, v_budget); - if (err) - return err; + ixgbevf_for_each_ring(ring, q_vector->rx) + adapter->rx_ring[ring->queue_index] = NULL; - err = netif_set_real_num_tx_queues(netdev, adapter->num_tx_queues); - if (err) - return err; + adapter->q_vector[v_idx] = NULL; + netif_napi_del(&q_vector->napi); - return netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues); + /* ixgbevf_get_stats() might access the rings on this vector, + * we must wait a grace period before freeing it. + */ + kfree_rcu(q_vector, rcu); } /** @@ -2515,35 +2580,53 @@ static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter) **/ static int ixgbevf_alloc_q_vectors(struct ixgbevf_adapter *adapter) { - int q_idx, num_q_vectors; - struct ixgbevf_q_vector *q_vector; + int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + int rxr_remaining = adapter->num_rx_queues; + int txr_remaining = adapter->num_tx_queues; + int rxr_idx = 0, txr_idx = 0, v_idx = 0; + int err; + + if (q_vectors >= (rxr_remaining + txr_remaining)) { + for (; rxr_remaining; v_idx++, q_vectors--) { + int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors); + + err = ixgbevf_alloc_q_vector(adapter, v_idx, + 0, 0, rqpv, rxr_idx); + if (err) + goto err_out; - num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + /* update counts and index */ + rxr_remaining -= rqpv; + rxr_idx += rqpv; + } + } + + for (; q_vectors; v_idx++, q_vectors--) { + int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors); + int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors); - for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { - q_vector = kzalloc(sizeof(struct ixgbevf_q_vector), GFP_KERNEL); - if (!q_vector) + err = ixgbevf_alloc_q_vector(adapter, v_idx, + tqpv, txr_idx, + rqpv, rxr_idx); + + if (err) goto err_out; - q_vector->adapter = adapter; - q_vector->v_idx = q_idx; - netif_napi_add(adapter->netdev, &q_vector->napi, - ixgbevf_poll, 64); - adapter->q_vector[q_idx] = q_vector; + + /* update counts and index */ + rxr_remaining -= rqpv; + rxr_idx += rqpv; + txr_remaining -= tqpv; + txr_idx += tqpv; } return 0; err_out: - while (q_idx) { - q_idx--; - q_vector = adapter->q_vector[q_idx]; -#ifdef CONFIG_NET_RX_BUSY_POLL - napi_hash_del(&q_vector->napi); -#endif - netif_napi_del(&q_vector->napi); - kfree(q_vector); - adapter->q_vector[q_idx] = NULL; + while (v_idx) { + v_idx--; + ixgbevf_free_q_vector(adapter, v_idx); } + return -ENOMEM; } @@ -2557,17 +2640,11 @@ err_out: **/ static void ixgbevf_free_q_vectors(struct ixgbevf_adapter *adapter) { - int q_idx, num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; - - for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { - struct ixgbevf_q_vector *q_vector = adapter->q_vector[q_idx]; + int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; - adapter->q_vector[q_idx] = NULL; -#ifdef CONFIG_NET_RX_BUSY_POLL - napi_hash_del(&q_vector->napi); -#endif - netif_napi_del(&q_vector->napi); - kfree(q_vector); + while (q_vectors) { + q_vectors--; + ixgbevf_free_q_vector(adapter, q_vectors); } } @@ -2611,12 +2688,6 @@ static int ixgbevf_init_interrupt_scheme(struct ixgbevf_adapter *adapter) goto err_alloc_q_vectors; } - err = ixgbevf_alloc_queues(adapter); - if (err) { - pr_err("Unable to allocate memory for queues\n"); - goto err_alloc_queues; - } - hw_dbg(&adapter->hw, "Multiqueue %s: Rx Queue count = %u, Tx Queue count = %u\n", (adapter->num_rx_queues > 1) ? "Enabled" : "Disabled", adapter->num_rx_queues, adapter->num_tx_queues); @@ -2624,8 +2695,6 @@ static int ixgbevf_init_interrupt_scheme(struct ixgbevf_adapter *adapter) set_bit(__IXGBEVF_DOWN, &adapter->state); return 0; -err_alloc_queues: - ixgbevf_free_q_vectors(adapter); err_alloc_q_vectors: ixgbevf_reset_interrupt_capability(adapter); err_set_interrupt: @@ -2641,17 +2710,6 @@ err_set_interrupt: **/ static void ixgbevf_clear_interrupt_scheme(struct ixgbevf_adapter *adapter) { - int i; - - for (i = 0; i < adapter->num_tx_queues; i++) { - kfree(adapter->tx_ring[i]); - adapter->tx_ring[i] = NULL; - } - for (i = 0; i < adapter->num_rx_queues; i++) { - kfree(adapter->rx_ring[i]); - adapter->rx_ring[i] = NULL; - } - adapter->num_tx_queues = 0; adapter->num_rx_queues = 0; @@ -3088,9 +3146,14 @@ static int ixgbevf_setup_all_tx_resources(struct ixgbevf_adapter *adapter) if (!err) continue; hw_dbg(&adapter->hw, "Allocation for Tx Queue %u failed\n", i); - break; + goto err_setup_tx; } + return 0; +err_setup_tx: + /* rewind the index freeing the rings as we go */ + while (i--) + ixgbevf_free_tx_resources(adapter->tx_ring[i]); return err; } @@ -3148,8 +3211,14 @@ static int ixgbevf_setup_all_rx_resources(struct ixgbevf_adapter *adapter) if (!err) continue; hw_dbg(&adapter->hw, "Allocation for Rx Queue %u failed\n", i); - break; + goto err_setup_rx; } + + return 0; +err_setup_rx: + /* rewind the index freeing the rings as we go */ + while (i--) + ixgbevf_free_rx_resources(adapter->rx_ring[i]); return err; } @@ -3244,28 +3313,31 @@ int ixgbevf_open(struct net_device *netdev) ixgbevf_configure(adapter); - /* Map the Tx/Rx rings to the vectors we were allotted. - * if request_irq will be called in this function map_rings - * must be called *before* up_complete - */ - ixgbevf_map_rings_to_vectors(adapter); - err = ixgbevf_request_irq(adapter); if (err) goto err_req_irq; + /* Notify the stack of the actual queue counts. */ + err = netif_set_real_num_tx_queues(netdev, adapter->num_tx_queues); + if (err) + goto err_set_queues; + + err = netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues); + if (err) + goto err_set_queues; + ixgbevf_up_complete(adapter); return 0; +err_set_queues: + ixgbevf_free_irq(adapter); err_req_irq: - ixgbevf_down(adapter); -err_setup_rx: ixgbevf_free_all_rx_resources(adapter); -err_setup_tx: +err_setup_rx: ixgbevf_free_all_tx_resources(adapter); +err_setup_tx: ixgbevf_reset(adapter); - err_setup_reset: return err; @@ -3707,11 +3779,10 @@ static int ixgbevf_maybe_stop_tx(struct ixgbevf_ring *tx_ring, int size) return __ixgbevf_maybe_stop_tx(tx_ring, size); } -static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static int ixgbevf_xmit_frame_ring(struct sk_buff *skb, + struct ixgbevf_ring *tx_ring) { - struct ixgbevf_adapter *adapter = netdev_priv(netdev); struct ixgbevf_tx_buffer *first; - struct ixgbevf_ring *tx_ring; int tso; u32 tx_flags = 0; u16 count = TXD_USE_COUNT(skb_headlen(skb)); @@ -3726,8 +3797,6 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } - tx_ring = adapter->tx_ring[skb->queue_mapping]; - /* need: 1 descriptor per page * PAGE_SIZE/IXGBE_MAX_DATA_PER_TXD, * + 1 desc for skb_headlen/IXGBE_MAX_DATA_PER_TXD, * + 2 desc gap to keep tail from touching head, @@ -3780,6 +3849,29 @@ out_drop: return NETDEV_TX_OK; } +static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbevf_ring *tx_ring; + + if (skb->len <= 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + /* The minimum packet size for olinfo paylen is 17 so pad the skb + * in order to meet this minimum size requirement. + */ + if (skb->len < 17) { + if (skb_padto(skb, 17)) + return NETDEV_TX_OK; + skb->len = 17; + } + + tx_ring = adapter->tx_ring[skb->queue_mapping]; + return ixgbevf_xmit_frame_ring(skb, tx_ring); +} + /** * ixgbevf_set_mac - Change the Ethernet Address of the NIC * @netdev: network interface device structure @@ -3839,6 +3931,9 @@ static int ixgbevf_change_mtu(struct net_device *netdev, int new_mtu) /* must set new MTU before calling down or up */ netdev->mtu = new_mtu; + if (netif_running(netdev)) + ixgbevf_reinit_locked(adapter); + return 0; } @@ -3917,17 +4012,11 @@ static int ixgbevf_resume(struct pci_dev *pdev) rtnl_lock(); err = ixgbevf_init_interrupt_scheme(adapter); + if (!err && netif_running(netdev)) + err = ixgbevf_open(netdev); rtnl_unlock(); - if (err) { - dev_err(&pdev->dev, "Cannot initialize interrupts\n"); + if (err) return err; - } - - if (netif_running(netdev)) { - err = ixgbevf_open(netdev); - if (err) - return err; - } netif_device_attach(netdev); @@ -3953,6 +4042,7 @@ static void ixgbevf_get_stats(struct net_device *netdev, stats->multicast = adapter->stats.vfmprc - adapter->stats.base_vfmprc; + rcu_read_lock(); for (i = 0; i < adapter->num_rx_queues; i++) { ring = adapter->rx_ring[i]; do { @@ -3974,6 +4064,7 @@ static void ixgbevf_get_stats(struct net_device *netdev, stats->tx_bytes += bytes; stats->tx_packets += packets; } + rcu_read_unlock(); } #define IXGBEVF_MAX_MAC_HDR_LEN 127 diff --git a/drivers/net/ethernet/natsemi/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c index d5b28884e21e..51fa82b429a3 100644 --- a/drivers/net/ethernet/natsemi/jazzsonic.c +++ b/drivers/net/ethernet/natsemi/jazzsonic.c @@ -60,14 +60,6 @@ do { \ *((volatile unsigned int *)dev->base_addr+(reg)) = (val); \ } while (0) - -/* use 0 for production, 1 for verification, >1 for debug */ -#ifdef SONIC_DEBUG -static unsigned int sonic_debug = SONIC_DEBUG; -#else -static unsigned int sonic_debug = 1; -#endif - /* * We cannot use station (ethernet) address prefixes to detect the * sonic controller since these are board manufacturer depended. @@ -117,7 +109,6 @@ static const struct net_device_ops sonic_netdev_ops = { static int sonic_probe1(struct net_device *dev) { - static unsigned version_printed; unsigned int silicon_revision; unsigned int val; struct sonic_local *lp = netdev_priv(dev); @@ -133,26 +124,17 @@ static int sonic_probe1(struct net_device *dev) * the expected location. */ silicon_revision = SONIC_READ(SONIC_SR); - if (sonic_debug > 1) - printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); - i = 0; while (known_revisions[i] != 0xffff && known_revisions[i] != silicon_revision) i++; if (known_revisions[i] == 0xffff) { - printk("SONIC ethernet controller not found (0x%4x)\n", - silicon_revision); + pr_info("SONIC ethernet controller not found (0x%4x)\n", + silicon_revision); goto out; } - if (sonic_debug && version_printed++ == 0) - printk(version); - - printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", - dev_name(lp->device), dev->base_addr); - /* * Put the sonic into software reset, then * retrieve and print the ethernet address. @@ -245,12 +227,16 @@ static int jazz_sonic_probe(struct platform_device *pdev) err = sonic_probe1(dev); if (err) goto out; + + pr_info("SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", + dev->base_addr, dev->dev_addr, dev->irq); + + sonic_msg_init(dev); + err = register_netdev(dev); if (err) goto out1; - printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq); - return 0; out1: @@ -262,8 +248,6 @@ out: } MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); -module_param(sonic_debug, int, 0); -MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); MODULE_ALIAS("platform:jazzsonic"); #include "sonic.c" diff --git a/drivers/net/ethernet/natsemi/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c index b922ab5cedea..0937fc2a928e 100644 --- a/drivers/net/ethernet/natsemi/macsonic.c +++ b/drivers/net/ethernet/natsemi/macsonic.c @@ -60,8 +60,6 @@ #include <asm/macints.h> #include <asm/mac_via.h> -static char mac_sonic_string[] = "macsonic"; - #include "sonic.h" /* These should basically be bus-size and endian independent (since @@ -72,15 +70,6 @@ static char mac_sonic_string[] = "macsonic"; #define SONIC_WRITE(reg,val) (nubus_writew(val, dev->base_addr + (reg * 4) \ + lp->reg_offset)) -/* use 0 for production, 1 for verification, >1 for debug */ -#ifdef SONIC_DEBUG -static unsigned int sonic_debug = SONIC_DEBUG; -#else -static unsigned int sonic_debug = 1; -#endif - -static int sonic_version_printed; - /* For onboard SONIC */ #define ONBOARD_SONIC_REGISTERS 0x50F0A000 #define ONBOARD_SONIC_PROM_BASE 0x50f08000 @@ -313,11 +302,6 @@ static int mac_onboard_sonic_probe(struct net_device *dev) int sr; bool commslot = macintosh_config->expansion_type == MAC_EXP_PDS_COMM; - if (!MACH_IS_MAC) - return -ENODEV; - - printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); - /* Bogus probing, on the models which may or may not have Ethernet (BTW, the Ethernet *is* always at the same address, and nothing else lives there, at least if Apple's @@ -327,13 +311,11 @@ static int mac_onboard_sonic_probe(struct net_device *dev) card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS); if (!card_present) { - printk("none.\n"); + pr_info("Onboard/comm-slot SONIC not found\n"); return -ENODEV; } } - printk("yes\n"); - /* Danger! My arms are flailing wildly! You *must* set lp->reg_offset * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */ dev->base_addr = ONBOARD_SONIC_REGISTERS; @@ -342,18 +324,10 @@ static int mac_onboard_sonic_probe(struct net_device *dev) else dev->irq = IRQ_NUBUS_9; - if (!sonic_version_printed) { - printk(KERN_INFO "%s", version); - sonic_version_printed = 1; - } - printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n", - dev_name(lp->device), dev->base_addr); - /* The PowerBook's SONIC is 16 bit always. */ if (macintosh_config->ident == MAC_MODEL_PB520) { lp->reg_offset = 0; lp->dma_bitmode = SONIC_BITMODE16; - sr = SONIC_READ(SONIC_SR); } else if (commslot) { /* Some of the comm-slot cards are 16 bit. But some of them are not. The 32-bit cards use offset 2 and @@ -370,22 +344,21 @@ static int mac_onboard_sonic_probe(struct net_device *dev) else { lp->dma_bitmode = SONIC_BITMODE16; lp->reg_offset = 0; - sr = SONIC_READ(SONIC_SR); } } else { /* All onboard cards are at offset 2 with 32 bit DMA. */ lp->reg_offset = 2; lp->dma_bitmode = SONIC_BITMODE32; - sr = SONIC_READ(SONIC_SR); } - printk(KERN_INFO - "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", - dev_name(lp->device), sr, lp->dma_bitmode?32:16, lp->reg_offset); -#if 0 /* This is sometimes useful to find out how MacOS configured the card. */ - printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device), - SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); -#endif + pr_info("Onboard/comm-slot SONIC, revision 0x%04x, %d bit DMA, register offset %d\n", + SONIC_READ(SONIC_SR), lp->dma_bitmode ? 32 : 16, + lp->reg_offset); + + /* This is sometimes useful to find out how MacOS configured the card */ + pr_debug("%s: DCR=0x%04x, DCR2=0x%04x\n", __func__, + SONIC_READ(SONIC_DCR) & 0xffff, + SONIC_READ(SONIC_DCR2) & 0xffff); /* Software reset, then initialize control registers. */ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); @@ -406,11 +379,14 @@ static int mac_onboard_sonic_probe(struct net_device *dev) /* Now look for the MAC address. */ mac_onboard_sonic_ethernet_addr(dev); + pr_info("SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", + dev->base_addr, dev->dev_addr, dev->irq); + /* Shared init code */ return macsonic_init(dev); } -static int mac_nubus_sonic_ethernet_addr(struct net_device *dev, +static int mac_sonic_nubus_ethernet_addr(struct net_device *dev, unsigned long prom_addr, int id) { int i; @@ -449,70 +425,49 @@ static int macsonic_ident(struct nubus_rsrc *fres) return -1; } -static int mac_nubus_sonic_probe(struct net_device *dev) +static int mac_sonic_nubus_probe_board(struct nubus_board *board, int id, + struct net_device *dev) { - static int slots; - struct nubus_rsrc *ndev = NULL; struct sonic_local* lp = netdev_priv(dev); unsigned long base_addr, prom_addr; u16 sonic_dcr; - int id = -1; int reg_offset, dma_bitmode; - /* Find the first SONIC that hasn't been initialized already */ - for_each_func_rsrc(ndev) { - if (ndev->category != NUBUS_CAT_NETWORK || - ndev->type != NUBUS_TYPE_ETHERNET) - continue; - - /* Have we seen it already? */ - if (slots & (1<<ndev->board->slot)) - continue; - slots |= 1<<ndev->board->slot; - - /* Is it one of ours? */ - if ((id = macsonic_ident(ndev)) != -1) - break; - } - - if (ndev == NULL) - return -ENODEV; - switch (id) { case MACSONIC_DUODOCK: - base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS; - prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE; + base_addr = board->slot_addr + DUODOCK_SONIC_REGISTERS; + prom_addr = board->slot_addr + DUODOCK_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; reg_offset = 2; dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE: - base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; - prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; + base_addr = board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = board->slot_addr + APPLE_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; reg_offset = 0; dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE16: - base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; - prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; + base_addr = board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = board->slot_addr + APPLE_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNALINK: - base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; - prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE; + base_addr = board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = board->slot_addr + DAYNALINK_PROM_BASE; sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNA: - base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS; - prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR; + base_addr = board->slot_addr + DAYNA_SONIC_REGISTERS; + prom_addr = board->slot_addr + DAYNA_SONIC_MAC_ADDR; sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; reg_offset = 0; @@ -528,21 +483,16 @@ static int mac_nubus_sonic_probe(struct net_device *dev) dev->base_addr = base_addr; lp->reg_offset = reg_offset; lp->dma_bitmode = dma_bitmode; - dev->irq = SLOT2IRQ(ndev->board->slot); + dev->irq = SLOT2IRQ(board->slot); - if (!sonic_version_printed) { - printk(KERN_INFO "%s", version); - sonic_version_printed = 1; - } - printk(KERN_INFO "%s: %s in slot %X\n", - dev_name(lp->device), ndev->board->name, ndev->board->slot); - printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", - dev_name(lp->device), SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset); + dev_info(&board->dev, "%s, revision 0x%04x, %d bit DMA, register offset %d\n", + board->name, SONIC_READ(SONIC_SR), + lp->dma_bitmode ? 32 : 16, lp->reg_offset); -#if 0 /* This is sometimes useful to find out how MacOS configured the card. */ - printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device), - SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); -#endif + /* This is sometimes useful to find out how MacOS configured the card */ + dev_dbg(&board->dev, "%s: DCR=0x%04x, DCR2=0x%04x\n", __func__, + SONIC_READ(SONIC_DCR) & 0xffff, + SONIC_READ(SONIC_DCR2) & 0xffff); /* Software reset, then initialize control registers. */ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); @@ -557,14 +507,17 @@ static int mac_nubus_sonic_probe(struct net_device *dev) SONIC_WRITE(SONIC_ISR, 0x7fff); /* Now look for the MAC address. */ - if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0) + if (mac_sonic_nubus_ethernet_addr(dev, prom_addr, id) != 0) return -ENODEV; + dev_info(&board->dev, "SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", + dev->base_addr, dev->dev_addr, dev->irq); + /* Shared init code */ return macsonic_init(dev); } -static int mac_sonic_probe(struct platform_device *pdev) +static int mac_sonic_platform_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; @@ -579,22 +532,16 @@ static int mac_sonic_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); platform_set_drvdata(pdev, dev); - /* This will catch fatal stuff like -ENOMEM as well as success */ err = mac_onboard_sonic_probe(dev); - if (err == 0) - goto found; - if (err != -ENODEV) - goto out; - err = mac_nubus_sonic_probe(dev); if (err) goto out; -found: + + sonic_msg_init(dev); + err = register_netdev(dev); if (err) goto out; - printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq); - return 0; out: @@ -604,13 +551,11 @@ out: } MODULE_DESCRIPTION("Macintosh SONIC ethernet driver"); -module_param(sonic_debug, int, 0); -MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); MODULE_ALIAS("platform:macsonic"); #include "sonic.c" -static int mac_sonic_device_remove(struct platform_device *pdev) +static int mac_sonic_platform_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct sonic_local* lp = netdev_priv(dev); @@ -623,12 +568,105 @@ static int mac_sonic_device_remove(struct platform_device *pdev) return 0; } -static struct platform_driver mac_sonic_driver = { - .probe = mac_sonic_probe, - .remove = mac_sonic_device_remove, - .driver = { - .name = mac_sonic_string, +static struct platform_driver mac_sonic_platform_driver = { + .probe = mac_sonic_platform_probe, + .remove = mac_sonic_platform_remove, + .driver = { + .name = "macsonic", + }, +}; + +static int mac_sonic_nubus_probe(struct nubus_board *board) +{ + struct net_device *ndev; + struct sonic_local *lp; + struct nubus_rsrc *fres; + int id = -1; + int err; + + /* The platform driver will handle a PDS or Comm Slot card (even if + * it has a pseudoslot declaration ROM). + */ + if (macintosh_config->expansion_type == MAC_EXP_PDS_COMM) + return -ENODEV; + + for_each_board_func_rsrc(board, fres) { + if (fres->category != NUBUS_CAT_NETWORK || + fres->type != NUBUS_TYPE_ETHERNET) + continue; + + id = macsonic_ident(fres); + if (id != -1) + break; + } + if (!fres) + return -ENODEV; + + ndev = alloc_etherdev(sizeof(struct sonic_local)); + if (!ndev) + return -ENOMEM; + + lp = netdev_priv(ndev); + lp->device = &board->dev; + SET_NETDEV_DEV(ndev, &board->dev); + + err = mac_sonic_nubus_probe_board(board, id, ndev); + if (err) + goto out; + + sonic_msg_init(ndev); + + err = register_netdev(ndev); + if (err) + goto out; + + nubus_set_drvdata(board, ndev); + + return 0; + +out: + free_netdev(ndev); + return err; +} + +static int mac_sonic_nubus_remove(struct nubus_board *board) +{ + struct net_device *ndev = nubus_get_drvdata(board); + struct sonic_local *lp = netdev_priv(ndev); + + unregister_netdev(ndev); + dma_free_coherent(lp->device, + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + lp->descriptors, lp->descriptors_laddr); + free_netdev(ndev); + + return 0; +} + +static struct nubus_driver mac_sonic_nubus_driver = { + .probe = mac_sonic_nubus_probe, + .remove = mac_sonic_nubus_remove, + .driver = { + .name = "macsonic-nubus", + .owner = THIS_MODULE, }, }; -module_platform_driver(mac_sonic_driver); +static int perr, nerr; + +static int __init mac_sonic_init(void) +{ + perr = platform_driver_register(&mac_sonic_platform_driver); + nerr = nubus_driver_register(&mac_sonic_nubus_driver); + return 0; +} +module_init(mac_sonic_init); + +static void __exit mac_sonic_exit(void) +{ + if (!perr) + platform_driver_unregister(&mac_sonic_platform_driver); + if (!nerr) + nubus_driver_unregister(&mac_sonic_nubus_driver); +} +module_exit(mac_sonic_exit); diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 612c7a44b26c..7ed08486ae23 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -33,7 +33,21 @@ * the NetBSD file "sys/arch/mac68k/dev/if_sn.c". */ +static unsigned int version_printed; +static int sonic_debug = -1; +module_param(sonic_debug, int, 0); +MODULE_PARM_DESC(sonic_debug, "debug message level"); + +static void sonic_msg_init(struct net_device *dev) +{ + struct sonic_local *lp = netdev_priv(dev); + + lp->msg_enable = netif_msg_init(sonic_debug, 0); + + if (version_printed++ == 0) + netif_dbg(lp, drv, dev, "%s", version); +} /* * Open/initialize the SONIC controller. @@ -47,8 +61,7 @@ static int sonic_open(struct net_device *dev) struct sonic_local *lp = netdev_priv(dev); int i; - if (sonic_debug > 2) - printk("sonic_open: initializing sonic driver.\n"); + netif_dbg(lp, ifup, dev, "%s: initializing sonic driver\n", __func__); for (i = 0; i < SONIC_NUM_RRS; i++) { struct sk_buff *skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2); @@ -95,8 +108,7 @@ static int sonic_open(struct net_device *dev) netif_start_queue(dev); - if (sonic_debug > 2) - printk("sonic_open: Initialization done.\n"); + netif_dbg(lp, ifup, dev, "%s: Initialization done\n", __func__); return 0; } @@ -110,8 +122,7 @@ static int sonic_close(struct net_device *dev) struct sonic_local *lp = netdev_priv(dev); int i; - if (sonic_debug > 2) - printk("sonic_close\n"); + netif_dbg(lp, ifdown, dev, "%s\n", __func__); netif_stop_queue(dev); @@ -205,8 +216,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) int length; int entry = lp->next_tx; - if (sonic_debug > 2) - printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev); + netif_dbg(lp, tx_queued, dev, "%s: skb=%p\n", __func__, skb); length = skb->len; if (length < ETH_ZLEN) { @@ -252,14 +262,12 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) lp->next_tx = (entry + 1) & SONIC_TDS_MASK; if (lp->tx_skb[lp->next_tx] != NULL) { /* The ring is full, the ISR has yet to process the next TD. */ - if (sonic_debug > 3) - printk("%s: stopping queue\n", dev->name); + netif_dbg(lp, tx_queued, dev, "%s: stopping queue\n", __func__); netif_stop_queue(dev); /* after this packet, wait for ISR to free up some TDAs */ } else netif_start_queue(dev); - if (sonic_debug > 2) - printk("sonic_send_packet: issuing Tx command\n"); + netif_dbg(lp, tx_queued, dev, "%s: issuing Tx command\n", __func__); SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); @@ -281,8 +289,7 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) do { if (status & SONIC_INT_PKTRX) { - if (sonic_debug > 2) - printk("%s: packet rx\n", dev->name); + netif_dbg(lp, intr, dev, "%s: packet rx\n", __func__); sonic_rx(dev); /* got packet(s) */ SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */ } @@ -299,8 +306,7 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) * still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear) */ - if (sonic_debug > 2) - printk("%s: tx done\n", dev->name); + netif_dbg(lp, intr, dev, "%s: tx done\n", __func__); while (lp->tx_skb[entry] != NULL) { if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0) @@ -346,20 +352,20 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) * check error conditions */ if (status & SONIC_INT_RFO) { - if (sonic_debug > 1) - printk("%s: rx fifo overrun\n", dev->name); + netif_dbg(lp, rx_err, dev, "%s: rx fifo overrun\n", + __func__); lp->stats.rx_fifo_errors++; SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */ } if (status & SONIC_INT_RDE) { - if (sonic_debug > 1) - printk("%s: rx descriptors exhausted\n", dev->name); + netif_dbg(lp, rx_err, dev, "%s: rx descriptors exhausted\n", + __func__); lp->stats.rx_dropped++; SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */ } if (status & SONIC_INT_RBAE) { - if (sonic_debug > 1) - printk("%s: rx buffer area exceeded\n", dev->name); + netif_dbg(lp, rx_err, dev, "%s: rx buffer area exceeded\n", + __func__); lp->stats.rx_dropped++; SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */ } @@ -380,8 +386,9 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) /* transmit error */ if (status & SONIC_INT_TXER) { - if ((SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) && (sonic_debug > 2)) - printk(KERN_ERR "%s: tx fifo underrun\n", dev->name); + if (SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) + netif_dbg(lp, tx_err, dev, "%s: tx fifo underrun\n", + __func__); SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */ } @@ -475,8 +482,8 @@ static void sonic_rx(struct net_device *dev) if (lp->cur_rwp >= lp->rra_end) lp->cur_rwp = lp->rra_laddr & 0xffff; SONIC_WRITE(SONIC_RWP, lp->cur_rwp); if (SONIC_READ(SONIC_ISR) & SONIC_INT_RBE) { - if (sonic_debug > 2) - printk("%s: rx buffer exhausted\n", dev->name); + netif_dbg(lp, rx_err, dev, "%s: rx buffer exhausted\n", + __func__); SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */ } } else @@ -542,9 +549,8 @@ static void sonic_multicast_list(struct net_device *dev) (netdev_mc_count(dev) > 15)) { rcr |= SONIC_RCR_AMC; } else { - if (sonic_debug > 2) - printk("sonic_multicast_list: mc_count %d\n", - netdev_mc_count(dev)); + netif_dbg(lp, ifup, dev, "%s: mc_count %d\n", __func__, + netdev_mc_count(dev)); sonic_set_cam_enable(dev, 1); /* always enable our own address */ i = 1; netdev_for_each_mc_addr(ha, dev) { @@ -562,8 +568,7 @@ static void sonic_multicast_list(struct net_device *dev) } } - if (sonic_debug > 2) - printk("sonic_multicast_list: setting RCR=%x\n", rcr); + netif_dbg(lp, ifup, dev, "%s: setting RCR=%x\n", __func__, rcr); SONIC_WRITE(SONIC_RCR, rcr); } @@ -596,8 +601,8 @@ static int sonic_init(struct net_device *dev) /* * initialize the receive resource area */ - if (sonic_debug > 2) - printk("sonic_init: initialize receive resource area\n"); + netif_dbg(lp, ifup, dev, "%s: initialize receive resource area\n", + __func__); for (i = 0; i < SONIC_NUM_RRS; i++) { u16 bufadr_l = (unsigned long)lp->rx_laddr[i] & 0xffff; @@ -622,8 +627,7 @@ static int sonic_init(struct net_device *dev) SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE >> 1) - (lp->dma_bitmode ? 2 : 1)); /* load the resource pointers */ - if (sonic_debug > 3) - printk("sonic_init: issuing RRRA command\n"); + netif_dbg(lp, ifup, dev, "%s: issuing RRRA command\n", __func__); SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA); i = 0; @@ -632,16 +636,17 @@ static int sonic_init(struct net_device *dev) break; } - if (sonic_debug > 2) - printk("sonic_init: status=%x i=%d\n", SONIC_READ(SONIC_CMD), i); + netif_dbg(lp, ifup, dev, "%s: status=%x, i=%d\n", __func__, + SONIC_READ(SONIC_CMD), i); /* * Initialize the receive descriptors so that they * become a circular linked list, ie. let the last * descriptor point to the first again. */ - if (sonic_debug > 2) - printk("sonic_init: initialize receive descriptors\n"); + netif_dbg(lp, ifup, dev, "%s: initialize receive descriptors\n", + __func__); + for (i=0; i<SONIC_NUM_RDS; i++) { sonic_rda_put(dev, i, SONIC_RD_STATUS, 0); sonic_rda_put(dev, i, SONIC_RD_PKTLEN, 0); @@ -664,8 +669,9 @@ static int sonic_init(struct net_device *dev) /* * initialize transmit descriptors */ - if (sonic_debug > 2) - printk("sonic_init: initialize transmit descriptors\n"); + netif_dbg(lp, ifup, dev, "%s: initialize transmit descriptors\n", + __func__); + for (i = 0; i < SONIC_NUM_TDS; i++) { sonic_tda_put(dev, i, SONIC_TD_STATUS, 0); sonic_tda_put(dev, i, SONIC_TD_CONFIG, 0); @@ -712,10 +718,8 @@ static int sonic_init(struct net_device *dev) if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD) break; } - if (sonic_debug > 2) { - printk("sonic_init: CMD=%x, ISR=%x\n, i=%d", - SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i); - } + netif_dbg(lp, ifup, dev, "%s: CMD=%x, ISR=%x, i=%d\n", __func__, + SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i); /* * enable receiver, disable loopback @@ -731,9 +735,8 @@ static int sonic_init(struct net_device *dev) if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0) printk(KERN_ERR "sonic_init: failed, status=%x\n", cmd); - if (sonic_debug > 2) - printk("sonic_init: new status=%x\n", - SONIC_READ(SONIC_CMD)); + netif_dbg(lp, ifup, dev, "%s: new status=%x\n", __func__, + SONIC_READ(SONIC_CMD)); return 0; } diff --git a/drivers/net/ethernet/natsemi/sonic.h b/drivers/net/ethernet/natsemi/sonic.h index 421b1a283fed..2b27f7049acb 100644 --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -319,6 +319,7 @@ struct sonic_local { unsigned int eol_rx; unsigned int eol_tx; /* last unacked transmit packet */ unsigned int next_tx; /* next free TD */ + int msg_enable; struct device *device; /* generic device */ struct net_device_stats stats; }; @@ -336,6 +337,7 @@ static struct net_device_stats *sonic_get_stats(struct net_device *dev); static void sonic_multicast_list(struct net_device *dev); static int sonic_init(struct net_device *dev); static void sonic_tx_timeout(struct net_device *dev); +static void sonic_msg_init(struct net_device *dev); /* Internal inlines for reading/writing DMA buffers. Note that bus size and endianness matter here, whereas they don't for registers, diff --git a/drivers/net/ethernet/natsemi/xtsonic.c b/drivers/net/ethernet/natsemi/xtsonic.c index 1817deea98a4..e1b886e87a76 100644 --- a/drivers/net/ethernet/natsemi/xtsonic.c +++ b/drivers/net/ethernet/natsemi/xtsonic.c @@ -73,14 +73,6 @@ extern void xtboard_get_ether_addr(unsigned char *buf); #define SONIC_WRITE(reg,val) \ *((volatile unsigned int *)dev->base_addr+reg) = val - -/* Use 0 for production, 1 for verification, and >2 for debug */ -#ifdef SONIC_DEBUG -static unsigned int sonic_debug = SONIC_DEBUG; -#else -static unsigned int sonic_debug = 1; -#endif - /* * We cannot use station (ethernet) address prefixes to detect the * sonic controller since these are board manufacturer depended. @@ -130,7 +122,6 @@ static const struct net_device_ops xtsonic_netdev_ops = { static int __init sonic_probe1(struct net_device *dev) { - static unsigned version_printed = 0; unsigned int silicon_revision; struct sonic_local *lp = netdev_priv(dev); unsigned int base_addr = dev->base_addr; @@ -146,23 +137,17 @@ static int __init sonic_probe1(struct net_device *dev) * the expected location. */ silicon_revision = SONIC_READ(SONIC_SR); - if (sonic_debug > 1) - printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); - i = 0; while ((known_revisions[i] != 0xffff) && (known_revisions[i] != silicon_revision)) i++; if (known_revisions[i] == 0xffff) { - printk("SONIC ethernet controller not found (0x%4x)\n", - silicon_revision); + pr_info("SONIC ethernet controller not found (0x%4x)\n", + silicon_revision); return -ENODEV; } - if (sonic_debug && version_printed++ == 0) - printk(version); - /* * Put the sonic into software reset, then retrieve ethernet address. * Note: we are assuming that the boot-loader has initialized the cam. @@ -273,12 +258,15 @@ int xtsonic_probe(struct platform_device *pdev) if ((err = sonic_probe1(dev))) goto out; + + pr_info("SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", + dev->base_addr, dev->dev_addr, dev->irq); + + sonic_msg_init(dev); + if ((err = register_netdev(dev))) goto out1; - printk("%s: SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", dev->name, - dev->base_addr, dev->dev_addr, dev->irq); - return 0; out1: @@ -290,8 +278,6 @@ out: } MODULE_DESCRIPTION("Xtensa XT2000 SONIC ethernet driver"); -module_param(sonic_debug, int, 0); -MODULE_PARM_DESC(sonic_debug, "xtsonic debug level (1-4)"); #include "sonic.c" diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 96db3283eecf..cc51286ee51f 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -736,8 +736,7 @@ struct ring_info { }; enum features { - RTL_FEATURE_MSI = (1 << 0), - RTL_FEATURE_GMII = (1 << 1), + RTL_FEATURE_GMII = (1 << 0), }; struct rtl8169_counters { @@ -7847,7 +7846,7 @@ static int rtl8169_close(struct net_device *dev) cancel_work_sync(&tp->wk.work); - free_irq(pdev->irq, dev); + pci_free_irq(pdev, 0, dev); dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, tp->RxPhyAddr); @@ -7903,9 +7902,8 @@ static int rtl_open(struct net_device *dev) rtl_request_firmware(tp); - retval = request_irq(pdev->irq, rtl8169_interrupt, - (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED, - dev->name, dev); + retval = pci_request_irq(pdev, 0, rtl8169_interrupt, NULL, dev, + dev->name); if (retval < 0) goto err_release_fw_2; @@ -8253,7 +8251,7 @@ static const struct rtl_cfg_info { .region = 2, .align = 8, .event_slow = SYSErr | LinkChg | RxOverflow, - .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI, + .features = RTL_FEATURE_GMII, .coalesce_info = rtl_coalesce_info_8168_8136, .default_ver = RTL_GIGA_MAC_VER_11, }, @@ -8263,32 +8261,26 @@ static const struct rtl_cfg_info { .align = 8, .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver | PCSTimeout, - .features = RTL_FEATURE_MSI, .coalesce_info = rtl_coalesce_info_8168_8136, .default_ver = RTL_GIGA_MAC_VER_13, } }; -/* Cfg9346_Unlock assumed. */ -static unsigned rtl_try_msi(struct rtl8169_private *tp, - const struct rtl_cfg_info *cfg) +static int rtl_alloc_irq(struct rtl8169_private *tp) { void __iomem *ioaddr = tp->mmio_addr; - unsigned msi = 0; - u8 cfg2; + unsigned int flags; - cfg2 = RTL_R8(Config2) & ~MSIEnable; - if (cfg->features & RTL_FEATURE_MSI) { - if (pci_enable_msi(tp->pci_dev)) { - netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n"); - } else { - cfg2 |= MSIEnable; - msi = RTL_FEATURE_MSI; - } + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { + RTL_W8(Cfg9346, Cfg9346_Unlock); + RTL_W8(Config2, RTL_R8(Config2) & ~MSIEnable); + RTL_W8(Cfg9346, Cfg9346_Lock); + flags = PCI_IRQ_LEGACY; + } else { + flags = PCI_IRQ_ALL_TYPES; } - if (tp->mac_version <= RTL_GIGA_MAC_VER_06) - RTL_W8(Config2, cfg2); - return msi; + + return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags); } DECLARE_RTL_COND(rtl_link_list_ready_cond) @@ -8497,9 +8489,11 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) chipset = tp->mac_version; tp->txd_version = rtl_chip_infos[chipset].txd_version; - RTL_W8(Cfg9346, Cfg9346_Unlock); - tp->features |= rtl_try_msi(tp, cfg); - RTL_W8(Cfg9346, Cfg9346_Lock); + rc = rtl_alloc_irq(tp); + if (rc < 0) { + netif_err(tp, probe, dev, "Can't allocate interrupt\n"); + return rc; + } /* override BIOS settings, use userspace tools to enable WOL */ __rtl8169_set_wol(tp, 0); diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 4502ff7bc19f..d3e1bc05ca9c 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -752,6 +752,7 @@ static struct sh_eth_cpu_data sh7757_data = { .rpadir = 1, .rpadir_value = 2 << 16, .rtrate = 1, + .dual_port = 1, }; #define SH_GIGA_ETH_BASE 0xfee00000UL @@ -830,6 +831,7 @@ static struct sh_eth_cpu_data sh7757_data_giga = { .no_trimd = 1, .no_ade = 1, .tsu = 1, + .dual_port = 1, }; /* SH7734 */ @@ -900,6 +902,7 @@ static struct sh_eth_cpu_data sh7763_data = { .tsu = 1, .irq_flags = IRQF_SHARED, .magic = 1, + .dual_port = 1, }; static struct sh_eth_cpu_data sh7619_data = { @@ -932,6 +935,7 @@ static struct sh_eth_cpu_data sh771x_data = { EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | EESIPR_PREIP | EESIPR_CERFIP, .tsu = 1, + .dual_port = 1, }; static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd) @@ -2915,7 +2919,7 @@ static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev, /* SuperH's TSU register init function */ static void sh_eth_tsu_init(struct sh_eth_private *mdp) { - if (sh_eth_is_rz_fast_ether(mdp)) { + if (!mdp->cd->dual_port) { sh_eth_tsu_write(mdp, 0, TSU_TEN); /* Disable all CAM entry */ sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, TSU_FWSLC); /* Enable POST registers */ diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 35bfeeb3fcdc..5bbaf9e56e92 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -509,6 +509,7 @@ struct sh_eth_cpu_data { unsigned rmiimode:1; /* EtherC has RMIIMODE register */ unsigned rtrate:1; /* EtherC has RTRATE register */ unsigned magic:1; /* EtherC has ECMR.MPDE and ECSR.MPD */ + unsigned dual_port:1; /* Dual EtherC/E-DMAC */ }; struct sh_eth_private { diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index b919e89a9b93..516dd59249d7 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1694,6 +1694,7 @@ static struct pernet_operations geneve_net_ops = { .exit_batch = geneve_exit_batch_net, .id = &geneve_net_id, .size = sizeof(struct geneve_net), + .async = true, }; static int __init geneve_init_module(void) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index f38e32a7ec9c..127edd23018f 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -1325,6 +1325,7 @@ static struct pernet_operations gtp_net_ops = { .exit = gtp_net_exit, .id = >p_net_id, .size = sizeof(struct gtp_net), + .async = true, }; static int __init gtp_init(void) diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig index 303ba4133920..8782f5655e3f 100644 --- a/drivers/net/ieee802154/Kconfig +++ b/drivers/net/ieee802154/Kconfig @@ -104,3 +104,14 @@ config IEEE802154_CA8210_DEBUGFS exposes a debugfs node for each CA8210 instance which allows direct use of the Cascoda API, exposing the 802.15.4 MAC management entities. + +config IEEE802154_MCR20A + tristate "MCR20A transceiver driver" + depends on IEEE802154_DRIVERS && MAC802154 + depends on SPI + ---help--- + Say Y here to enable the MCR20A SPI 802.15.4 wireless + controller. + + This driver can also be built as a module. To do so, say M here. + the module will be called 'mcr20a'. diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile index bea1de5e726c..104744d5a668 100644 --- a/drivers/net/ieee802154/Makefile +++ b/drivers/net/ieee802154/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o obj-$(CONFIG_IEEE802154_CA8210) += ca8210.o +obj-$(CONFIG_IEEE802154_MCR20A) += mcr20a.o diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c new file mode 100644 index 000000000000..d9eb22a52551 --- /dev/null +++ b/drivers/net/ieee802154/mcr20a.c @@ -0,0 +1,1413 @@ +/* + * Driver for NXP MCR20A 802.15.4 Wireless-PAN Networking controller + * + * Copyright (C) 2018 Xue Liu <liuxuenetmail@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/spi/spi.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> +#include <linux/skbuff.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <linux/ieee802154.h> +#include <linux/debugfs.h> + +#include <net/mac802154.h> +#include <net/cfg802154.h> + +#include <linux/device.h> + +#include "mcr20a.h" + +#define SPI_COMMAND_BUFFER 3 + +#define REGISTER_READ BIT(7) +#define REGISTER_WRITE (0 << 7) +#define REGISTER_ACCESS (0 << 6) +#define PACKET_BUFF_BURST_ACCESS BIT(6) +#define PACKET_BUFF_BYTE_ACCESS BIT(5) + +#define MCR20A_WRITE_REG(x) (x) +#define MCR20A_READ_REG(x) (REGISTER_READ | (x)) +#define MCR20A_BURST_READ_PACKET_BUF (0xC0) +#define MCR20A_BURST_WRITE_PACKET_BUF (0x40) + +#define MCR20A_CMD_REG 0x80 +#define MCR20A_CMD_REG_MASK 0x3f +#define MCR20A_CMD_WRITE 0x40 +#define MCR20A_CMD_FB 0x20 + +/* Number of Interrupt Request Status Register */ +#define MCR20A_IRQSTS_NUM 2 /* only IRQ_STS1 and IRQ_STS2 */ + +/* MCR20A CCA Type */ +enum { + MCR20A_CCA_ED, // energy detect - CCA bit not active, + // not to be used for T and CCCA sequences + MCR20A_CCA_MODE1, // energy detect - CCA bit ACTIVE + MCR20A_CCA_MODE2, // 802.15.4 compliant signal detect - CCA bit ACTIVE + MCR20A_CCA_MODE3 +}; + +enum { + MCR20A_XCVSEQ_IDLE = 0x00, + MCR20A_XCVSEQ_RX = 0x01, + MCR20A_XCVSEQ_TX = 0x02, + MCR20A_XCVSEQ_CCA = 0x03, + MCR20A_XCVSEQ_TR = 0x04, + MCR20A_XCVSEQ_CCCA = 0x05, +}; + +/* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */ +#define MCR20A_MIN_CHANNEL (11) +#define MCR20A_MAX_CHANNEL (26) +#define MCR20A_CHANNEL_SPACING (5) + +/* MCR20A CCA Threshold constans */ +#define MCR20A_MIN_CCA_THRESHOLD (0x6EU) +#define MCR20A_MAX_CCA_THRESHOLD (0x00U) + +/* version 0C */ +#define MCR20A_OVERWRITE_VERSION (0x0C) + +/* MCR20A PLL configurations */ +static const u8 PLL_INT[16] = { + /* 2405 */ 0x0B, /* 2410 */ 0x0B, /* 2415 */ 0x0B, + /* 2420 */ 0x0B, /* 2425 */ 0x0B, /* 2430 */ 0x0B, + /* 2435 */ 0x0C, /* 2440 */ 0x0C, /* 2445 */ 0x0C, + /* 2450 */ 0x0C, /* 2455 */ 0x0C, /* 2460 */ 0x0C, + /* 2465 */ 0x0D, /* 2470 */ 0x0D, /* 2475 */ 0x0D, + /* 2480 */ 0x0D +}; + +static const u8 PLL_FRAC[16] = { + /* 2405 */ 0x28, /* 2410 */ 0x50, /* 2415 */ 0x78, + /* 2420 */ 0xA0, /* 2425 */ 0xC8, /* 2430 */ 0xF0, + /* 2435 */ 0x18, /* 2440 */ 0x40, /* 2445 */ 0x68, + /* 2450 */ 0x90, /* 2455 */ 0xB8, /* 2460 */ 0xE0, + /* 2465 */ 0x08, /* 2470 */ 0x30, /* 2475 */ 0x58, + /* 2480 */ 0x80 +}; + +static const struct reg_sequence mar20a_iar_overwrites[] = { + { IAR_MISC_PAD_CTRL, 0x02 }, + { IAR_VCO_CTRL1, 0xB3 }, + { IAR_VCO_CTRL2, 0x07 }, + { IAR_PA_TUNING, 0x71 }, + { IAR_CHF_IBUF, 0x2F }, + { IAR_CHF_QBUF, 0x2F }, + { IAR_CHF_IRIN, 0x24 }, + { IAR_CHF_QRIN, 0x24 }, + { IAR_CHF_IL, 0x24 }, + { IAR_CHF_QL, 0x24 }, + { IAR_CHF_CC1, 0x32 }, + { IAR_CHF_CCL, 0x1D }, + { IAR_CHF_CC2, 0x2D }, + { IAR_CHF_IROUT, 0x24 }, + { IAR_CHF_QROUT, 0x24 }, + { IAR_PA_CAL, 0x28 }, + { IAR_AGC_THR1, 0x55 }, + { IAR_AGC_THR2, 0x2D }, + { IAR_ATT_RSSI1, 0x5F }, + { IAR_ATT_RSSI2, 0x8F }, + { IAR_RSSI_OFFSET, 0x61 }, + { IAR_CHF_PMA_GAIN, 0x03 }, + { IAR_CCA1_THRESH, 0x50 }, + { IAR_CORR_NVAL, 0x13 }, + { IAR_ACKDELAY, 0x3D }, +}; + +#define MCR20A_VALID_CHANNELS (0x07FFF800) + +struct mcr20a_platform_data { + int rst_gpio; +}; + +#define MCR20A_MAX_BUF (127) + +#define printdev(X) (&X->spi->dev) + +/* regmap information for Direct Access Register (DAR) access */ +#define MCR20A_DAR_WRITE 0x01 +#define MCR20A_DAR_READ 0x00 +#define MCR20A_DAR_NUMREGS 0x3F + +/* regmap information for Indirect Access Register (IAR) access */ +#define MCR20A_IAR_ACCESS 0x80 +#define MCR20A_IAR_NUMREGS 0xBEFF + +/* Read/Write SPI Commands for DAR and IAR registers. */ +#define MCR20A_READSHORT(reg) ((reg) << 1) +#define MCR20A_WRITESHORT(reg) ((reg) << 1 | 1) +#define MCR20A_READLONG(reg) (1 << 15 | (reg) << 5) +#define MCR20A_WRITELONG(reg) (1 << 15 | (reg) << 5 | 1 << 4) + +/* Type definitions for link configuration of instantiable layers */ +#define MCR20A_PHY_INDIRECT_QUEUE_SIZE (12) + +static bool +mcr20a_dar_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DAR_IRQ_STS1: + case DAR_IRQ_STS2: + case DAR_IRQ_STS3: + case DAR_PHY_CTRL1: + case DAR_PHY_CTRL2: + case DAR_PHY_CTRL3: + case DAR_PHY_CTRL4: + case DAR_SRC_CTRL: + case DAR_SRC_ADDRS_SUM_LSB: + case DAR_SRC_ADDRS_SUM_MSB: + case DAR_T3CMP_LSB: + case DAR_T3CMP_MSB: + case DAR_T3CMP_USB: + case DAR_T2PRIMECMP_LSB: + case DAR_T2PRIMECMP_MSB: + case DAR_T1CMP_LSB: + case DAR_T1CMP_MSB: + case DAR_T1CMP_USB: + case DAR_T2CMP_LSB: + case DAR_T2CMP_MSB: + case DAR_T2CMP_USB: + case DAR_T4CMP_LSB: + case DAR_T4CMP_MSB: + case DAR_T4CMP_USB: + case DAR_PLL_INT0: + case DAR_PLL_FRAC0_LSB: + case DAR_PLL_FRAC0_MSB: + case DAR_PA_PWR: + /* no DAR_ACM */ + case DAR_OVERWRITE_VER: + case DAR_CLK_OUT_CTRL: + case DAR_PWR_MODES: + return true; + default: + return false; + } +} + +static bool +mcr20a_dar_readable(struct device *dev, unsigned int reg) +{ + bool rc; + + /* all writeable are also readable */ + rc = mcr20a_dar_writeable(dev, reg); + if (rc) + return rc; + + /* readonly regs */ + switch (reg) { + case DAR_RX_FRM_LEN: + case DAR_CCA1_ED_FNL: + case DAR_EVENT_TMR_LSB: + case DAR_EVENT_TMR_MSB: + case DAR_EVENT_TMR_USB: + case DAR_TIMESTAMP_LSB: + case DAR_TIMESTAMP_MSB: + case DAR_TIMESTAMP_USB: + case DAR_SEQ_STATE: + case DAR_LQI_VALUE: + case DAR_RSSI_CCA_CONT: + return true; + default: + return false; + } +} + +static bool +mcr20a_dar_volatile(struct device *dev, unsigned int reg) +{ + /* can be changed during runtime */ + switch (reg) { + case DAR_IRQ_STS1: + case DAR_IRQ_STS2: + case DAR_IRQ_STS3: + /* use them in spi_async and regmap so it's volatile */ + return true; + default: + return false; + } +} + +static bool +mcr20a_dar_precious(struct device *dev, unsigned int reg) +{ + /* don't clear irq line on read */ + switch (reg) { + case DAR_IRQ_STS1: + case DAR_IRQ_STS2: + case DAR_IRQ_STS3: + return true; + default: + return false; + } +} + +static const struct regmap_config mcr20a_dar_regmap = { + .name = "mcr20a_dar", + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = REGISTER_ACCESS | REGISTER_WRITE, + .read_flag_mask = REGISTER_ACCESS | REGISTER_READ, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = mcr20a_dar_writeable, + .readable_reg = mcr20a_dar_readable, + .volatile_reg = mcr20a_dar_volatile, + .precious_reg = mcr20a_dar_precious, + .fast_io = true, + .can_multi_write = true, +}; + +static bool +mcr20a_iar_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case IAR_XTAL_TRIM: + case IAR_PMC_LP_TRIM: + case IAR_MACPANID0_LSB: + case IAR_MACPANID0_MSB: + case IAR_MACSHORTADDRS0_LSB: + case IAR_MACSHORTADDRS0_MSB: + case IAR_MACLONGADDRS0_0: + case IAR_MACLONGADDRS0_8: + case IAR_MACLONGADDRS0_16: + case IAR_MACLONGADDRS0_24: + case IAR_MACLONGADDRS0_32: + case IAR_MACLONGADDRS0_40: + case IAR_MACLONGADDRS0_48: + case IAR_MACLONGADDRS0_56: + case IAR_RX_FRAME_FILTER: + case IAR_PLL_INT1: + case IAR_PLL_FRAC1_LSB: + case IAR_PLL_FRAC1_MSB: + case IAR_MACPANID1_LSB: + case IAR_MACPANID1_MSB: + case IAR_MACSHORTADDRS1_LSB: + case IAR_MACSHORTADDRS1_MSB: + case IAR_MACLONGADDRS1_0: + case IAR_MACLONGADDRS1_8: + case IAR_MACLONGADDRS1_16: + case IAR_MACLONGADDRS1_24: + case IAR_MACLONGADDRS1_32: + case IAR_MACLONGADDRS1_40: + case IAR_MACLONGADDRS1_48: + case IAR_MACLONGADDRS1_56: + case IAR_DUAL_PAN_CTRL: + case IAR_DUAL_PAN_DWELL: + case IAR_CCA1_THRESH: + case IAR_CCA1_ED_OFFSET_COMP: + case IAR_LQI_OFFSET_COMP: + case IAR_CCA_CTRL: + case IAR_CCA2_CORR_PEAKS: + case IAR_CCA2_CORR_THRESH: + case IAR_TMR_PRESCALE: + case IAR_ANT_PAD_CTRL: + case IAR_MISC_PAD_CTRL: + case IAR_BSM_CTRL: + case IAR_RNG: + case IAR_RX_WTR_MARK: + case IAR_SOFT_RESET: + case IAR_TXDELAY: + case IAR_ACKDELAY: + case IAR_CORR_NVAL: + case IAR_ANT_AGC_CTRL: + case IAR_AGC_THR1: + case IAR_AGC_THR2: + case IAR_PA_CAL: + case IAR_ATT_RSSI1: + case IAR_ATT_RSSI2: + case IAR_RSSI_OFFSET: + case IAR_XTAL_CTRL: + case IAR_CHF_PMA_GAIN: + case IAR_CHF_IBUF: + case IAR_CHF_QBUF: + case IAR_CHF_IRIN: + case IAR_CHF_QRIN: + case IAR_CHF_IL: + case IAR_CHF_QL: + case IAR_CHF_CC1: + case IAR_CHF_CCL: + case IAR_CHF_CC2: + case IAR_CHF_IROUT: + case IAR_CHF_QROUT: + case IAR_PA_TUNING: + case IAR_VCO_CTRL1: + case IAR_VCO_CTRL2: + return true; + default: + return false; + } +} + +static bool +mcr20a_iar_readable(struct device *dev, unsigned int reg) +{ + bool rc; + + /* all writeable are also readable */ + rc = mcr20a_iar_writeable(dev, reg); + if (rc) + return rc; + + /* readonly regs */ + switch (reg) { + case IAR_PART_ID: + case IAR_DUAL_PAN_STS: + case IAR_RX_BYTE_COUNT: + case IAR_FILTERFAIL_CODE1: + case IAR_FILTERFAIL_CODE2: + case IAR_RSSI: + return true; + default: + return false; + } +} + +static bool +mcr20a_iar_volatile(struct device *dev, unsigned int reg) +{ +/* can be changed during runtime */ + switch (reg) { + case IAR_DUAL_PAN_STS: + case IAR_RX_BYTE_COUNT: + case IAR_FILTERFAIL_CODE1: + case IAR_FILTERFAIL_CODE2: + case IAR_RSSI: + return true; + default: + return false; + } +} + +static const struct regmap_config mcr20a_iar_regmap = { + .name = "mcr20a_iar", + .reg_bits = 16, + .val_bits = 8, + .write_flag_mask = REGISTER_ACCESS | REGISTER_WRITE | IAR_INDEX, + .read_flag_mask = REGISTER_ACCESS | REGISTER_READ | IAR_INDEX, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = mcr20a_iar_writeable, + .readable_reg = mcr20a_iar_readable, + .volatile_reg = mcr20a_iar_volatile, + .fast_io = true, +}; + +struct mcr20a_local { + struct spi_device *spi; + + struct ieee802154_hw *hw; + struct mcr20a_platform_data *pdata; + struct regmap *regmap_dar; + struct regmap *regmap_iar; + + u8 *buf; + + bool is_tx; + + /* for writing tx buffer */ + struct spi_message tx_buf_msg; + u8 tx_header[1]; + /* burst buffer write command */ + struct spi_transfer tx_xfer_header; + u8 tx_len[1]; + /* len of tx packet */ + struct spi_transfer tx_xfer_len; + /* data of tx packet */ + struct spi_transfer tx_xfer_buf; + struct sk_buff *tx_skb; + + /* for read length rxfifo */ + struct spi_message reg_msg; + u8 reg_cmd[1]; + u8 reg_data[MCR20A_IRQSTS_NUM]; + struct spi_transfer reg_xfer_cmd; + struct spi_transfer reg_xfer_data; + + /* receive handling */ + struct spi_message rx_buf_msg; + u8 rx_header[1]; + struct spi_transfer rx_xfer_header; + u8 rx_lqi[1]; + struct spi_transfer rx_xfer_lqi; + u8 rx_buf[MCR20A_MAX_BUF]; + struct spi_transfer rx_xfer_buf; + + /* isr handling for reading intstat */ + struct spi_message irq_msg; + u8 irq_header[1]; + u8 irq_data[MCR20A_IRQSTS_NUM]; + struct spi_transfer irq_xfer_data; + struct spi_transfer irq_xfer_header; +}; + +static void +mcr20a_write_tx_buf_complete(void *context) +{ + struct mcr20a_local *lp = context; + int ret; + + dev_dbg(printdev(lp), "%s\n", __func__); + + lp->reg_msg.complete = NULL; + lp->reg_cmd[0] = MCR20A_WRITE_REG(DAR_PHY_CTRL1); + lp->reg_data[0] = MCR20A_XCVSEQ_TX; + lp->reg_xfer_data.len = 1; + + ret = spi_async(lp->spi, &lp->reg_msg); + if (ret) + dev_err(printdev(lp), "failed to set SEQ TX\n"); +} + +static int +mcr20a_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +{ + struct mcr20a_local *lp = hw->priv; + + dev_dbg(printdev(lp), "%s\n", __func__); + + lp->tx_skb = skb; + + print_hex_dump_debug("mcr20a tx: ", DUMP_PREFIX_OFFSET, 16, 1, + skb->data, skb->len, 0); + + lp->is_tx = 1; + + lp->reg_msg.complete = NULL; + lp->reg_cmd[0] = MCR20A_WRITE_REG(DAR_PHY_CTRL1); + lp->reg_data[0] = MCR20A_XCVSEQ_IDLE; + lp->reg_xfer_data.len = 1; + + return spi_async(lp->spi, &lp->reg_msg); +} + +static int +mcr20a_ed(struct ieee802154_hw *hw, u8 *level) +{ + WARN_ON(!level); + *level = 0xbe; + return 0; +} + +static int +mcr20a_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel) +{ + struct mcr20a_local *lp = hw->priv; + int ret; + + dev_dbg(printdev(lp), "%s\n", __func__); + + /* freqency = ((PLL_INT+64) + (PLL_FRAC/65536)) * 32 MHz */ + ret = regmap_write(lp->regmap_dar, DAR_PLL_INT0, PLL_INT[channel - 11]); + if (ret) + return ret; + ret = regmap_write(lp->regmap_dar, DAR_PLL_FRAC0_LSB, 0x00); + if (ret) + return ret; + ret = regmap_write(lp->regmap_dar, DAR_PLL_FRAC0_MSB, + PLL_FRAC[channel - 11]); + if (ret) + return ret; + + return 0; +} + +static int +mcr20a_start(struct ieee802154_hw *hw) +{ + struct mcr20a_local *lp = hw->priv; + int ret; + + dev_dbg(printdev(lp), "%s\n", __func__); + + /* No slotted operation */ + dev_dbg(printdev(lp), "no slotted operation\n"); + ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1, + DAR_PHY_CTRL1_SLOTTED, 0x0); + + /* enable irq */ + enable_irq(lp->spi->irq); + + /* Unmask SEQ interrupt */ + ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL2, + DAR_PHY_CTRL2_SEQMSK, 0x0); + + /* Start the RX sequence */ + dev_dbg(printdev(lp), "start the RX sequence\n"); + ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1, + DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_RX); + + return 0; +} + +static void +mcr20a_stop(struct ieee802154_hw *hw) +{ + struct mcr20a_local *lp = hw->priv; + + dev_dbg(printdev(lp), "%s\n", __func__); + + /* stop all running sequence */ + regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1, + DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_IDLE); + + /* disable irq */ + disable_irq(lp->spi->irq); +} + +static int +mcr20a_set_hw_addr_filt(struct ieee802154_hw *hw, + struct ieee802154_hw_addr_filt *filt, + unsigned long changed) +{ + struct mcr20a_local *lp = hw->priv; + + dev_dbg(printdev(lp), "%s\n", __func__); + + if (changed & IEEE802154_AFILT_SADDR_CHANGED) { + u16 addr = le16_to_cpu(filt->short_addr); + + regmap_write(lp->regmap_iar, IAR_MACSHORTADDRS0_LSB, addr); + regmap_write(lp->regmap_iar, IAR_MACSHORTADDRS0_MSB, addr >> 8); + } + + if (changed & IEEE802154_AFILT_PANID_CHANGED) { + u16 pan = le16_to_cpu(filt->pan_id); + + regmap_write(lp->regmap_iar, IAR_MACPANID0_LSB, pan); + regmap_write(lp->regmap_iar, IAR_MACPANID0_MSB, pan >> 8); + } + + if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) { + u8 addr[8], i; + + memcpy(addr, &filt->ieee_addr, 8); + for (i = 0; i < 8; i++) + regmap_write(lp->regmap_iar, + IAR_MACLONGADDRS0_0 + i, addr[i]); + } + + if (changed & IEEE802154_AFILT_PANC_CHANGED) { + if (filt->pan_coord) { + regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4, + DAR_PHY_CTRL4_PANCORDNTR0, 0x10); + } else { + regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4, + DAR_PHY_CTRL4_PANCORDNTR0, 0x00); + } + } + + return 0; +} + +/* -30 dBm to 10 dBm */ +#define MCR20A_MAX_TX_POWERS 0x14 +static const s32 mcr20a_powers[MCR20A_MAX_TX_POWERS + 1] = { + -3000, -2800, -2600, -2400, -2200, -2000, -1800, -1600, -1400, + -1200, -1000, -800, -600, -400, -200, 0, 200, 400, 600, 800, 1000 +}; + +static int +mcr20a_set_txpower(struct ieee802154_hw *hw, s32 mbm) +{ + struct mcr20a_local *lp = hw->priv; + u32 i; + + dev_dbg(printdev(lp), "%s(%d)\n", __func__, mbm); + + for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) { + if (lp->hw->phy->supported.tx_powers[i] == mbm) + return regmap_write(lp->regmap_dar, DAR_PA_PWR, + ((i + 8) & 0x1F)); + } + + return -EINVAL; +} + +#define MCR20A_MAX_ED_LEVELS MCR20A_MIN_CCA_THRESHOLD +static s32 mcr20a_ed_levels[MCR20A_MAX_ED_LEVELS + 1]; + +static int +mcr20a_set_cca_mode(struct ieee802154_hw *hw, + const struct wpan_phy_cca *cca) +{ + struct mcr20a_local *lp = hw->priv; + unsigned int cca_mode = 0xff; + bool cca_mode_and = false; + int ret; + + dev_dbg(printdev(lp), "%s\n", __func__); + + /* mapping 802.15.4 to driver spec */ + switch (cca->mode) { + case NL802154_CCA_ENERGY: + cca_mode = MCR20A_CCA_MODE1; + break; + case NL802154_CCA_CARRIER: + cca_mode = MCR20A_CCA_MODE2; + break; + case NL802154_CCA_ENERGY_CARRIER: + switch (cca->opt) { + case NL802154_CCA_OPT_ENERGY_CARRIER_AND: + cca_mode = MCR20A_CCA_MODE3; + cca_mode_and = true; + break; + case NL802154_CCA_OPT_ENERGY_CARRIER_OR: + cca_mode = MCR20A_CCA_MODE3; + cca_mode_and = false; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4, + DAR_PHY_CTRL4_CCATYPE_MASK, + cca_mode << DAR_PHY_CTRL4_CCATYPE_SHIFT); + if (ret < 0) + return ret; + + if (cca_mode == MCR20A_CCA_MODE3) { + if (cca_mode_and) { + ret = regmap_update_bits(lp->regmap_iar, IAR_CCA_CTRL, + IAR_CCA_CTRL_CCA3_AND_NOT_OR, + 0x08); + } else { + ret = regmap_update_bits(lp->regmap_iar, + IAR_CCA_CTRL, + IAR_CCA_CTRL_CCA3_AND_NOT_OR, + 0x00); + } + if (ret < 0) + return ret; + } + + return ret; +} + +static int +mcr20a_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) +{ + struct mcr20a_local *lp = hw->priv; + u32 i; + + dev_dbg(printdev(lp), "%s\n", __func__); + + for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) { + if (hw->phy->supported.cca_ed_levels[i] == mbm) + return regmap_write(lp->regmap_iar, IAR_CCA1_THRESH, i); + } + + return 0; +} + +static int +mcr20a_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) +{ + struct mcr20a_local *lp = hw->priv; + int ret; + u8 rx_frame_filter_reg = 0x0; + u8 val; + + dev_dbg(printdev(lp), "%s(%d)\n", __func__, on); + + if (on) { + /* All frame types accepted*/ + val |= DAR_PHY_CTRL4_PROMISCUOUS; + rx_frame_filter_reg &= ~(IAR_RX_FRAME_FLT_FRM_VER); + rx_frame_filter_reg |= (IAR_RX_FRAME_FLT_ACK_FT | + IAR_RX_FRAME_FLT_NS_FT); + + ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4, + DAR_PHY_CTRL4_PROMISCUOUS, + DAR_PHY_CTRL4_PROMISCUOUS); + if (ret < 0) + return ret; + + ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER, + rx_frame_filter_reg); + if (ret < 0) + return ret; + } else { + ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4, + DAR_PHY_CTRL4_PROMISCUOUS, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER, + IAR_RX_FRAME_FLT_FRM_VER | + IAR_RX_FRAME_FLT_BEACON_FT | + IAR_RX_FRAME_FLT_DATA_FT | + IAR_RX_FRAME_FLT_CMD_FT); + if (ret < 0) + return ret; + } + + return 0; +} + +static const struct ieee802154_ops mcr20a_hw_ops = { + .owner = THIS_MODULE, + .xmit_async = mcr20a_xmit, + .ed = mcr20a_ed, + .set_channel = mcr20a_set_channel, + .start = mcr20a_start, + .stop = mcr20a_stop, + .set_hw_addr_filt = mcr20a_set_hw_addr_filt, + .set_txpower = mcr20a_set_txpower, + .set_cca_mode = mcr20a_set_cca_mode, + .set_cca_ed_level = mcr20a_set_cca_ed_level, + .set_promiscuous_mode = mcr20a_set_promiscuous_mode, +}; + +static int +mcr20a_request_rx(struct mcr20a_local *lp) +{ + dev_dbg(printdev(lp), "%s\n", __func__); + + /* Start the RX sequence */ + regmap_update_bits_async(lp->regmap_dar, DAR_PHY_CTRL1, + DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_RX); + + return 0; +} + +static void +mcr20a_handle_rx_read_buf_complete(void *context) +{ + struct mcr20a_local *lp = context; + u8 len = lp->reg_data[0] & DAR_RX_FRAME_LENGTH_MASK; + struct sk_buff *skb; + + dev_dbg(printdev(lp), "%s\n", __func__); + + dev_dbg(printdev(lp), "RX is done\n"); + + if (!ieee802154_is_valid_psdu_len(len)) { + dev_vdbg(&lp->spi->dev, "corrupted frame received\n"); + len = IEEE802154_MTU; + } + + len = len - 2; /* get rid of frame check field */ + + skb = dev_alloc_skb(len); + if (!skb) + return; + + memcpy(skb_put(skb, len), lp->rx_buf, len); + ieee802154_rx_irqsafe(lp->hw, skb, lp->rx_lqi[0]); + + print_hex_dump_debug("mcr20a rx: ", DUMP_PREFIX_OFFSET, 16, 1, + lp->rx_buf, len, 0); + pr_debug("mcr20a rx: lqi: %02hhx\n", lp->rx_lqi[0]); + + /* start RX sequence */ + mcr20a_request_rx(lp); +} + +static void +mcr20a_handle_rx_read_len_complete(void *context) +{ + struct mcr20a_local *lp = context; + u8 len; + int ret; + + dev_dbg(printdev(lp), "%s\n", __func__); + + /* get the length of received frame */ + len = lp->reg_data[0] & DAR_RX_FRAME_LENGTH_MASK; + dev_dbg(printdev(lp), "frame len : %d\n", len); + + /* prepare to read the rx buf */ + lp->rx_buf_msg.complete = mcr20a_handle_rx_read_buf_complete; + lp->rx_header[0] = MCR20A_BURST_READ_PACKET_BUF; + lp->rx_xfer_buf.len = len; + + ret = spi_async(lp->spi, &lp->rx_buf_msg); + if (ret) + dev_err(printdev(lp), "failed to read rx buffer length\n"); +} + +static int +mcr20a_handle_rx(struct mcr20a_local *lp) +{ + dev_dbg(printdev(lp), "%s\n", __func__); + lp->reg_msg.complete = mcr20a_handle_rx_read_len_complete; + lp->reg_cmd[0] = MCR20A_READ_REG(DAR_RX_FRM_LEN); + lp->reg_xfer_data.len = 1; + + return spi_async(lp->spi, &lp->reg_msg); +} + +static int +mcr20a_handle_tx_complete(struct mcr20a_local *lp) +{ + dev_dbg(printdev(lp), "%s\n", __func__); + + ieee802154_xmit_complete(lp->hw, lp->tx_skb, false); + + return mcr20a_request_rx(lp); +} + +static int +mcr20a_handle_tx(struct mcr20a_local *lp) +{ + int ret; + + dev_dbg(printdev(lp), "%s\n", __func__); + + /* write tx buffer */ + lp->tx_header[0] = MCR20A_BURST_WRITE_PACKET_BUF; + /* add 2 bytes of FCS */ + lp->tx_len[0] = lp->tx_skb->len + 2; + lp->tx_xfer_buf.tx_buf = lp->tx_skb->data; + /* add 1 byte psduLength */ + lp->tx_xfer_buf.len = lp->tx_skb->len + 1; + + ret = spi_async(lp->spi, &lp->tx_buf_msg); + if (ret) { + dev_err(printdev(lp), "SPI write Failed for TX buf\n"); + return ret; + } + + return 0; +} + +static void +mcr20a_irq_clean_complete(void *context) +{ + struct mcr20a_local *lp = context; + u8 seq_state = lp->irq_data[DAR_IRQ_STS1] & DAR_PHY_CTRL1_XCVSEQ_MASK; + + dev_dbg(printdev(lp), "%s\n", __func__); + + enable_irq(lp->spi->irq); + + dev_dbg(printdev(lp), "IRQ STA1 (%02x) STA2 (%02x)\n", + lp->irq_data[DAR_IRQ_STS1], lp->irq_data[DAR_IRQ_STS2]); + + switch (seq_state) { + /* TX IRQ, RX IRQ and SEQ IRQ */ + case (0x03): + if (lp->is_tx) { + lp->is_tx = 0; + dev_dbg(printdev(lp), "TX is done. No ACK\n"); + mcr20a_handle_tx_complete(lp); + } + break; + case (0x05): + /* rx is starting */ + dev_dbg(printdev(lp), "RX is starting\n"); + mcr20a_handle_rx(lp); + break; + case (0x07): + if (lp->is_tx) { + /* tx is done */ + lp->is_tx = 0; + dev_dbg(printdev(lp), "TX is done. Get ACK\n"); + mcr20a_handle_tx_complete(lp); + } else { + /* rx is starting */ + dev_dbg(printdev(lp), "RX is starting\n"); + mcr20a_handle_rx(lp); + } + break; + case (0x01): + if (lp->is_tx) { + dev_dbg(printdev(lp), "TX is starting\n"); + mcr20a_handle_tx(lp); + } else { + dev_dbg(printdev(lp), "MCR20A is stop\n"); + } + break; + } +} + +static void mcr20a_irq_status_complete(void *context) +{ + int ret; + struct mcr20a_local *lp = context; + + dev_dbg(printdev(lp), "%s\n", __func__); + regmap_update_bits_async(lp->regmap_dar, DAR_PHY_CTRL1, + DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_IDLE); + + lp->reg_msg.complete = mcr20a_irq_clean_complete; + lp->reg_cmd[0] = MCR20A_WRITE_REG(DAR_IRQ_STS1); + memcpy(lp->reg_data, lp->irq_data, MCR20A_IRQSTS_NUM); + lp->reg_xfer_data.len = MCR20A_IRQSTS_NUM; + + ret = spi_async(lp->spi, &lp->reg_msg); + + if (ret) + dev_err(printdev(lp), "failed to clean irq status\n"); +} + +static irqreturn_t mcr20a_irq_isr(int irq, void *data) +{ + struct mcr20a_local *lp = data; + int ret; + + disable_irq_nosync(irq); + + lp->irq_header[0] = MCR20A_READ_REG(DAR_IRQ_STS1); + /* read IRQSTSx */ + ret = spi_async(lp->spi, &lp->irq_msg); + if (ret) { + enable_irq(irq); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int mcr20a_get_platform_data(struct spi_device *spi, + struct mcr20a_platform_data *pdata) +{ + int ret = 0; + + if (!spi->dev.of_node) + return -EINVAL; + + pdata->rst_gpio = of_get_named_gpio(spi->dev.of_node, "rst_b-gpio", 0); + dev_dbg(&spi->dev, "rst_b-gpio: %d\n", pdata->rst_gpio); + + return ret; +} + +static void mcr20a_hw_setup(struct mcr20a_local *lp) +{ + u8 i; + struct ieee802154_hw *hw = lp->hw; + struct wpan_phy *phy = lp->hw->phy; + + dev_dbg(printdev(lp), "%s\n", __func__); + + phy->symbol_duration = 16; + phy->lifs_period = 40; + phy->sifs_period = 12; + + hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | + IEEE802154_HW_AFILT | + IEEE802154_HW_PROMISCUOUS; + + phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL | + WPAN_PHY_FLAG_CCA_MODE; + + phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) | + BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER); + phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) | + BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR); + + /* initiating cca_ed_levels */ + for (i = MCR20A_MAX_CCA_THRESHOLD; i < MCR20A_MIN_CCA_THRESHOLD + 1; + ++i) { + mcr20a_ed_levels[i] = -i * 100; + } + + phy->supported.cca_ed_levels = mcr20a_ed_levels; + phy->supported.cca_ed_levels_size = ARRAY_SIZE(mcr20a_ed_levels); + + phy->cca.mode = NL802154_CCA_ENERGY; + + phy->supported.channels[0] = MCR20A_VALID_CHANNELS; + phy->current_page = 0; + /* MCR20A default reset value */ + phy->current_channel = 20; + phy->symbol_duration = 16; + phy->supported.tx_powers = mcr20a_powers; + phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers); + phy->cca_ed_level = phy->supported.cca_ed_levels[75]; + phy->transmit_power = phy->supported.tx_powers[0x0F]; +} + +static void +mcr20a_setup_tx_spi_messages(struct mcr20a_local *lp) +{ + spi_message_init(&lp->tx_buf_msg); + lp->tx_buf_msg.context = lp; + lp->tx_buf_msg.complete = mcr20a_write_tx_buf_complete; + + lp->tx_xfer_header.len = 1; + lp->tx_xfer_header.tx_buf = lp->tx_header; + + lp->tx_xfer_len.len = 1; + lp->tx_xfer_len.tx_buf = lp->tx_len; + + spi_message_add_tail(&lp->tx_xfer_header, &lp->tx_buf_msg); + spi_message_add_tail(&lp->tx_xfer_len, &lp->tx_buf_msg); + spi_message_add_tail(&lp->tx_xfer_buf, &lp->tx_buf_msg); +} + +static void +mcr20a_setup_rx_spi_messages(struct mcr20a_local *lp) +{ + spi_message_init(&lp->reg_msg); + lp->reg_msg.context = lp; + + lp->reg_xfer_cmd.len = 1; + lp->reg_xfer_cmd.tx_buf = lp->reg_cmd; + lp->reg_xfer_cmd.rx_buf = lp->reg_cmd; + + lp->reg_xfer_data.rx_buf = lp->reg_data; + lp->reg_xfer_data.tx_buf = lp->reg_data; + + spi_message_add_tail(&lp->reg_xfer_cmd, &lp->reg_msg); + spi_message_add_tail(&lp->reg_xfer_data, &lp->reg_msg); + + spi_message_init(&lp->rx_buf_msg); + lp->rx_buf_msg.context = lp; + lp->rx_buf_msg.complete = mcr20a_handle_rx_read_buf_complete; + lp->rx_xfer_header.len = 1; + lp->rx_xfer_header.tx_buf = lp->rx_header; + lp->rx_xfer_header.rx_buf = lp->rx_header; + + lp->rx_xfer_buf.rx_buf = lp->rx_buf; + + lp->rx_xfer_lqi.len = 1; + lp->rx_xfer_lqi.rx_buf = lp->rx_lqi; + + spi_message_add_tail(&lp->rx_xfer_header, &lp->rx_buf_msg); + spi_message_add_tail(&lp->rx_xfer_buf, &lp->rx_buf_msg); + spi_message_add_tail(&lp->rx_xfer_lqi, &lp->rx_buf_msg); +} + +static void +mcr20a_setup_irq_spi_messages(struct mcr20a_local *lp) +{ + spi_message_init(&lp->irq_msg); + lp->irq_msg.context = lp; + lp->irq_msg.complete = mcr20a_irq_status_complete; + lp->irq_xfer_header.len = 1; + lp->irq_xfer_header.tx_buf = lp->irq_header; + lp->irq_xfer_header.rx_buf = lp->irq_header; + + lp->irq_xfer_data.len = MCR20A_IRQSTS_NUM; + lp->irq_xfer_data.rx_buf = lp->irq_data; + + spi_message_add_tail(&lp->irq_xfer_header, &lp->irq_msg); + spi_message_add_tail(&lp->irq_xfer_data, &lp->irq_msg); +} + +static int +mcr20a_phy_init(struct mcr20a_local *lp) +{ + u8 index; + unsigned int phy_reg = 0; + int ret; + + dev_dbg(printdev(lp), "%s\n", __func__); + + /* Disable Tristate on COCO MISO for SPI reads */ + ret = regmap_write(lp->regmap_iar, IAR_MISC_PAD_CTRL, 0x02); + if (ret) + goto err_ret; + + /* Clear all PP IRQ bits in IRQSTS1 to avoid unexpected interrupts + * immediately after init + */ + ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS1, 0xEF); + if (ret) + goto err_ret; + + /* Clear all PP IRQ bits in IRQSTS2 */ + ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS2, + DAR_IRQSTS2_ASM_IRQ | DAR_IRQSTS2_PB_ERR_IRQ | + DAR_IRQSTS2_WAKE_IRQ); + if (ret) + goto err_ret; + + /* Disable all timer interrupts */ + ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS3, 0xFF); + if (ret) + goto err_ret; + + /* PHY_CTRL1 : default HW settings + AUTOACK enabled */ + ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1, + DAR_PHY_CTRL1_AUTOACK, DAR_PHY_CTRL1_AUTOACK); + + /* PHY_CTRL2 : disable all interrupts */ + ret = regmap_write(lp->regmap_dar, DAR_PHY_CTRL2, 0xFF); + if (ret) + goto err_ret; + + /* PHY_CTRL3 : disable all timers and remaining interrupts */ + ret = regmap_write(lp->regmap_dar, DAR_PHY_CTRL3, + DAR_PHY_CTRL3_ASM_MSK | DAR_PHY_CTRL3_PB_ERR_MSK | + DAR_PHY_CTRL3_WAKE_MSK); + if (ret) + goto err_ret; + + /* SRC_CTRL : enable Acknowledge Frame Pending and + * Source Address Matching Enable + */ + ret = regmap_write(lp->regmap_dar, DAR_SRC_CTRL, + DAR_SRC_CTRL_ACK_FRM_PND | + (DAR_SRC_CTRL_INDEX << DAR_SRC_CTRL_INDEX_SHIFT)); + if (ret) + goto err_ret; + + /* RX_FRAME_FILTER */ + /* FRM_VER[1:0] = b11. Accept FrameVersion 0 and 1 packets */ + ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER, + IAR_RX_FRAME_FLT_FRM_VER | + IAR_RX_FRAME_FLT_BEACON_FT | + IAR_RX_FRAME_FLT_DATA_FT | + IAR_RX_FRAME_FLT_CMD_FT); + if (ret) + goto err_ret; + + dev_info(printdev(lp), "MCR20A DAR overwrites version: 0x%02x\n", + MCR20A_OVERWRITE_VERSION); + + /* Overwrites direct registers */ + ret = regmap_write(lp->regmap_dar, DAR_OVERWRITE_VER, + MCR20A_OVERWRITE_VERSION); + if (ret) + goto err_ret; + + /* Overwrites indirect registers */ + ret = regmap_multi_reg_write(lp->regmap_iar, mar20a_iar_overwrites, + ARRAY_SIZE(mar20a_iar_overwrites)); + if (ret) + goto err_ret; + + /* Clear HW indirect queue */ + dev_dbg(printdev(lp), "clear HW indirect queue\n"); + for (index = 0; index < MCR20A_PHY_INDIRECT_QUEUE_SIZE; index++) { + phy_reg = (u8)(((index & DAR_SRC_CTRL_INDEX) << + DAR_SRC_CTRL_INDEX_SHIFT) + | (DAR_SRC_CTRL_SRCADDR_EN) + | (DAR_SRC_CTRL_INDEX_DISABLE)); + ret = regmap_write(lp->regmap_dar, DAR_SRC_CTRL, phy_reg); + if (ret) + goto err_ret; + phy_reg = 0; + } + + /* Assign HW Indirect hash table to PAN0 */ + ret = regmap_read(lp->regmap_iar, IAR_DUAL_PAN_CTRL, &phy_reg); + if (ret) + goto err_ret; + + /* Clear current lvl */ + phy_reg &= ~IAR_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_MSK; + + /* Set new lvl */ + phy_reg |= MCR20A_PHY_INDIRECT_QUEUE_SIZE << + IAR_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_SHIFT; + ret = regmap_write(lp->regmap_iar, IAR_DUAL_PAN_CTRL, phy_reg); + if (ret) + goto err_ret; + + /* Set CCA threshold to -75 dBm */ + ret = regmap_write(lp->regmap_iar, IAR_CCA1_THRESH, 0x4B); + if (ret) + goto err_ret; + + /* Set prescaller to obtain 1 symbol (16us) timebase */ + ret = regmap_write(lp->regmap_iar, IAR_TMR_PRESCALE, 0x05); + if (ret) + goto err_ret; + + /* Enable autodoze mode. */ + ret = regmap_update_bits(lp->regmap_dar, DAR_PWR_MODES, + DAR_PWR_MODES_AUTODOZE, + DAR_PWR_MODES_AUTODOZE); + if (ret) + goto err_ret; + + /* Disable clk_out */ + ret = regmap_update_bits(lp->regmap_dar, DAR_CLK_OUT_CTRL, + DAR_CLK_OUT_CTRL_EN, 0x0); + if (ret) + goto err_ret; + + return 0; + +err_ret: + return ret; +} + +static int +mcr20a_probe(struct spi_device *spi) +{ + struct ieee802154_hw *hw; + struct mcr20a_local *lp; + struct mcr20a_platform_data *pdata; + int irq_type; + int ret = -ENOMEM; + + dev_dbg(&spi->dev, "%s\n", __func__); + + if (!spi->irq) { + dev_err(&spi->dev, "no IRQ specified\n"); + return -EINVAL; + } + + pdata = kmalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + /* set mcr20a platform data */ + ret = mcr20a_get_platform_data(spi, pdata); + if (ret < 0) { + dev_crit(&spi->dev, "mcr20a_get_platform_data failed.\n"); + return ret; + } + + /* init reset gpio */ + if (gpio_is_valid(pdata->rst_gpio)) { + ret = devm_gpio_request_one(&spi->dev, pdata->rst_gpio, + GPIOF_OUT_INIT_HIGH, "reset"); + if (ret) + return ret; + } + + /* reset mcr20a */ + if (gpio_is_valid(pdata->rst_gpio)) { + usleep_range(10, 20); + gpio_set_value_cansleep(pdata->rst_gpio, 0); + usleep_range(10, 20); + gpio_set_value_cansleep(pdata->rst_gpio, 1); + usleep_range(120, 240); + } + + /* allocate ieee802154_hw and private data */ + hw = ieee802154_alloc_hw(sizeof(*lp), &mcr20a_hw_ops); + if (!hw) { + dev_crit(&spi->dev, "ieee802154_alloc_hw failed\n"); + return -ENOMEM; + } + + /* init mcr20a local data */ + lp = hw->priv; + lp->hw = hw; + lp->spi = spi; + lp->spi->dev.platform_data = pdata; + lp->pdata = pdata; + + /* init ieee802154_hw */ + hw->parent = &spi->dev; + ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); + + /* init buf */ + lp->buf = devm_kzalloc(&spi->dev, SPI_COMMAND_BUFFER, GFP_KERNEL); + + if (!lp->buf) + return -ENOMEM; + + mcr20a_setup_tx_spi_messages(lp); + mcr20a_setup_rx_spi_messages(lp); + mcr20a_setup_irq_spi_messages(lp); + + /* setup regmap */ + lp->regmap_dar = devm_regmap_init_spi(spi, &mcr20a_dar_regmap); + if (IS_ERR(lp->regmap_dar)) { + ret = PTR_ERR(lp->regmap_dar); + dev_err(&spi->dev, "Failed to allocate dar map: %d\n", + ret); + goto free_dev; + } + + lp->regmap_iar = devm_regmap_init_spi(spi, &mcr20a_iar_regmap); + if (IS_ERR(lp->regmap_iar)) { + ret = PTR_ERR(lp->regmap_iar); + dev_err(&spi->dev, "Failed to allocate iar map: %d\n", ret); + goto free_dev; + } + + mcr20a_hw_setup(lp); + + spi_set_drvdata(spi, lp); + + ret = mcr20a_phy_init(lp); + if (ret < 0) { + dev_crit(&spi->dev, "mcr20a_phy_init failed\n"); + goto free_dev; + } + + irq_type = irq_get_trigger_type(spi->irq); + if (!irq_type) + irq_type = IRQF_TRIGGER_FALLING; + + ret = devm_request_irq(&spi->dev, spi->irq, mcr20a_irq_isr, + irq_type, dev_name(&spi->dev), lp); + if (ret) { + dev_err(&spi->dev, "could not request_irq for mcr20a\n"); + ret = -ENODEV; + goto free_dev; + } + + /* disable_irq by default and wait for starting hardware */ + disable_irq(spi->irq); + + ret = ieee802154_register_hw(hw); + if (ret) { + dev_crit(&spi->dev, "ieee802154_register_hw failed\n"); + goto free_dev; + } + + return ret; + +free_dev: + ieee802154_free_hw(lp->hw); + + return ret; +} + +static int mcr20a_remove(struct spi_device *spi) +{ + struct mcr20a_local *lp = spi_get_drvdata(spi); + + dev_dbg(&spi->dev, "%s\n", __func__); + + ieee802154_unregister_hw(lp->hw); + ieee802154_free_hw(lp->hw); + + return 0; +} + +static const struct of_device_id mcr20a_of_match[] = { + { .compatible = "nxp,mcr20a", }, + { }, +}; +MODULE_DEVICE_TABLE(of, mcr20a_of_match); + +static const struct spi_device_id mcr20a_device_id[] = { + { .name = "mcr20a", }, + { }, +}; +MODULE_DEVICE_TABLE(spi, mcr20a_device_id); + +static struct spi_driver mcr20a_driver = { + .id_table = mcr20a_device_id, + .driver = { + .of_match_table = of_match_ptr(mcr20a_of_match), + .name = "mcr20a", + }, + .probe = mcr20a_probe, + .remove = mcr20a_remove, +}; + +module_spi_driver(mcr20a_driver); + +MODULE_DESCRIPTION("MCR20A Transceiver Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Xue Liu <liuxuenetmail@gmail>"); diff --git a/drivers/net/ieee802154/mcr20a.h b/drivers/net/ieee802154/mcr20a.h new file mode 100644 index 000000000000..6da4fd00b3c5 --- /dev/null +++ b/drivers/net/ieee802154/mcr20a.h @@ -0,0 +1,498 @@ +/* + * Driver for NXP MCR20A 802.15.4 Wireless-PAN Networking controller + * + * Copyright (C) 2018 Xue Liu <liuxuenetmail@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _MCR20A_H +#define _MCR20A_H + +/* Direct Accress Register */ +#define DAR_IRQ_STS1 0x00 +#define DAR_IRQ_STS2 0x01 +#define DAR_IRQ_STS3 0x02 +#define DAR_PHY_CTRL1 0x03 +#define DAR_PHY_CTRL2 0x04 +#define DAR_PHY_CTRL3 0x05 +#define DAR_RX_FRM_LEN 0x06 +#define DAR_PHY_CTRL4 0x07 +#define DAR_SRC_CTRL 0x08 +#define DAR_SRC_ADDRS_SUM_LSB 0x09 +#define DAR_SRC_ADDRS_SUM_MSB 0x0A +#define DAR_CCA1_ED_FNL 0x0B +#define DAR_EVENT_TMR_LSB 0x0C +#define DAR_EVENT_TMR_MSB 0x0D +#define DAR_EVENT_TMR_USB 0x0E +#define DAR_TIMESTAMP_LSB 0x0F +#define DAR_TIMESTAMP_MSB 0x10 +#define DAR_TIMESTAMP_USB 0x11 +#define DAR_T3CMP_LSB 0x12 +#define DAR_T3CMP_MSB 0x13 +#define DAR_T3CMP_USB 0x14 +#define DAR_T2PRIMECMP_LSB 0x15 +#define DAR_T2PRIMECMP_MSB 0x16 +#define DAR_T1CMP_LSB 0x17 +#define DAR_T1CMP_MSB 0x18 +#define DAR_T1CMP_USB 0x19 +#define DAR_T2CMP_LSB 0x1A +#define DAR_T2CMP_MSB 0x1B +#define DAR_T2CMP_USB 0x1C +#define DAR_T4CMP_LSB 0x1D +#define DAR_T4CMP_MSB 0x1E +#define DAR_T4CMP_USB 0x1F +#define DAR_PLL_INT0 0x20 +#define DAR_PLL_FRAC0_LSB 0x21 +#define DAR_PLL_FRAC0_MSB 0x22 +#define DAR_PA_PWR 0x23 +#define DAR_SEQ_STATE 0x24 +#define DAR_LQI_VALUE 0x25 +#define DAR_RSSI_CCA_CONT 0x26 +/*------------------ 0x27 */ +#define DAR_ASM_CTRL1 0x28 +#define DAR_ASM_CTRL2 0x29 +#define DAR_ASM_DATA_0 0x2A +#define DAR_ASM_DATA_1 0x2B +#define DAR_ASM_DATA_2 0x2C +#define DAR_ASM_DATA_3 0x2D +#define DAR_ASM_DATA_4 0x2E +#define DAR_ASM_DATA_5 0x2F +#define DAR_ASM_DATA_6 0x30 +#define DAR_ASM_DATA_7 0x31 +#define DAR_ASM_DATA_8 0x32 +#define DAR_ASM_DATA_9 0x33 +#define DAR_ASM_DATA_A 0x34 +#define DAR_ASM_DATA_B 0x35 +#define DAR_ASM_DATA_C 0x36 +#define DAR_ASM_DATA_D 0x37 +#define DAR_ASM_DATA_E 0x38 +#define DAR_ASM_DATA_F 0x39 +/*----------------------- 0x3A */ +#define DAR_OVERWRITE_VER 0x3B +#define DAR_CLK_OUT_CTRL 0x3C +#define DAR_PWR_MODES 0x3D +#define IAR_INDEX 0x3E +#define IAR_DATA 0x3F + +/* Indirect Resgister Memory */ +#define IAR_PART_ID 0x00 +#define IAR_XTAL_TRIM 0x01 +#define IAR_PMC_LP_TRIM 0x02 +#define IAR_MACPANID0_LSB 0x03 +#define IAR_MACPANID0_MSB 0x04 +#define IAR_MACSHORTADDRS0_LSB 0x05 +#define IAR_MACSHORTADDRS0_MSB 0x06 +#define IAR_MACLONGADDRS0_0 0x07 +#define IAR_MACLONGADDRS0_8 0x08 +#define IAR_MACLONGADDRS0_16 0x09 +#define IAR_MACLONGADDRS0_24 0x0A +#define IAR_MACLONGADDRS0_32 0x0B +#define IAR_MACLONGADDRS0_40 0x0C +#define IAR_MACLONGADDRS0_48 0x0D +#define IAR_MACLONGADDRS0_56 0x0E +#define IAR_RX_FRAME_FILTER 0x0F +#define IAR_PLL_INT1 0x10 +#define IAR_PLL_FRAC1_LSB 0x11 +#define IAR_PLL_FRAC1_MSB 0x12 +#define IAR_MACPANID1_LSB 0x13 +#define IAR_MACPANID1_MSB 0x14 +#define IAR_MACSHORTADDRS1_LSB 0x15 +#define IAR_MACSHORTADDRS1_MSB 0x16 +#define IAR_MACLONGADDRS1_0 0x17 +#define IAR_MACLONGADDRS1_8 0x18 +#define IAR_MACLONGADDRS1_16 0x19 +#define IAR_MACLONGADDRS1_24 0x1A +#define IAR_MACLONGADDRS1_32 0x1B +#define IAR_MACLONGADDRS1_40 0x1C +#define IAR_MACLONGADDRS1_48 0x1D +#define IAR_MACLONGADDRS1_56 0x1E +#define IAR_DUAL_PAN_CTRL 0x1F +#define IAR_DUAL_PAN_DWELL 0x20 +#define IAR_DUAL_PAN_STS 0x21 +#define IAR_CCA1_THRESH 0x22 +#define IAR_CCA1_ED_OFFSET_COMP 0x23 +#define IAR_LQI_OFFSET_COMP 0x24 +#define IAR_CCA_CTRL 0x25 +#define IAR_CCA2_CORR_PEAKS 0x26 +#define IAR_CCA2_CORR_THRESH 0x27 +#define IAR_TMR_PRESCALE 0x28 +/*-------------------- 0x29 */ +#define IAR_GPIO_DATA 0x2A +#define IAR_GPIO_DIR 0x2B +#define IAR_GPIO_PUL_EN 0x2C +#define IAR_GPIO_PUL_SEL 0x2D +#define IAR_GPIO_DS 0x2E +/*------------------ 0x2F */ +#define IAR_ANT_PAD_CTRL 0x30 +#define IAR_MISC_PAD_CTRL 0x31 +#define IAR_BSM_CTRL 0x32 +/*------------------- 0x33 */ +#define IAR_RNG 0x34 +#define IAR_RX_BYTE_COUNT 0x35 +#define IAR_RX_WTR_MARK 0x36 +#define IAR_SOFT_RESET 0x37 +#define IAR_TXDELAY 0x38 +#define IAR_ACKDELAY 0x39 +#define IAR_SEQ_MGR_CTRL 0x3A +#define IAR_SEQ_MGR_STS 0x3B +#define IAR_SEQ_T_STS 0x3C +#define IAR_ABORT_STS 0x3D +#define IAR_CCCA_BUSY_CNT 0x3E +#define IAR_SRC_ADDR_CHECKSUM1 0x3F +#define IAR_SRC_ADDR_CHECKSUM2 0x40 +#define IAR_SRC_TBL_VALID1 0x41 +#define IAR_SRC_TBL_VALID2 0x42 +#define IAR_FILTERFAIL_CODE1 0x43 +#define IAR_FILTERFAIL_CODE2 0x44 +#define IAR_SLOT_PRELOAD 0x45 +/*-------------------- 0x46 */ +#define IAR_CORR_VT 0x47 +#define IAR_SYNC_CTRL 0x48 +#define IAR_PN_LSB_0 0x49 +#define IAR_PN_LSB_1 0x4A +#define IAR_PN_MSB_0 0x4B +#define IAR_PN_MSB_1 0x4C +#define IAR_CORR_NVAL 0x4D +#define IAR_TX_MODE_CTRL 0x4E +#define IAR_SNF_THR 0x4F +#define IAR_FAD_THR 0x50 +#define IAR_ANT_AGC_CTRL 0x51 +#define IAR_AGC_THR1 0x52 +#define IAR_AGC_THR2 0x53 +#define IAR_AGC_HYS 0x54 +#define IAR_AFC 0x55 +/*------------------- 0x56 */ +/*------------------- 0x57 */ +#define IAR_PHY_STS 0x58 +#define IAR_RX_MAX_CORR 0x59 +#define IAR_RX_MAX_PREAMBLE 0x5A +#define IAR_RSSI 0x5B +/*------------------- 0x5C */ +/*------------------- 0x5D */ +#define IAR_PLL_DIG_CTRL 0x5E +#define IAR_VCO_CAL 0x5F +#define IAR_VCO_BEST_DIFF 0x60 +#define IAR_VCO_BIAS 0x61 +#define IAR_KMOD_CTRL 0x62 +#define IAR_KMOD_CAL 0x63 +#define IAR_PA_CAL 0x64 +#define IAR_PA_PWRCAL 0x65 +#define IAR_ATT_RSSI1 0x66 +#define IAR_ATT_RSSI2 0x67 +#define IAR_RSSI_OFFSET 0x68 +#define IAR_RSSI_SLOPE 0x69 +#define IAR_RSSI_CAL1 0x6A +#define IAR_RSSI_CAL2 0x6B +/*------------------- 0x6C */ +/*------------------- 0x6D */ +#define IAR_XTAL_CTRL 0x6E +#define IAR_XTAL_COMP_MIN 0x6F +#define IAR_XTAL_COMP_MAX 0x70 +#define IAR_XTAL_GM 0x71 +/*------------------- 0x72 */ +/*------------------- 0x73 */ +#define IAR_LNA_TUNE 0x74 +#define IAR_LNA_AGCGAIN 0x75 +/*------------------- 0x76 */ +/*------------------- 0x77 */ +#define IAR_CHF_PMA_GAIN 0x78 +#define IAR_CHF_IBUF 0x79 +#define IAR_CHF_QBUF 0x7A +#define IAR_CHF_IRIN 0x7B +#define IAR_CHF_QRIN 0x7C +#define IAR_CHF_IL 0x7D +#define IAR_CHF_QL 0x7E +#define IAR_CHF_CC1 0x7F +#define IAR_CHF_CCL 0x80 +#define IAR_CHF_CC2 0x81 +#define IAR_CHF_IROUT 0x82 +#define IAR_CHF_QROUT 0x83 +/*------------------- 0x84 */ +/*------------------- 0x85 */ +#define IAR_RSSI_CTRL 0x86 +/*------------------- 0x87 */ +/*------------------- 0x88 */ +#define IAR_PA_BIAS 0x89 +#define IAR_PA_TUNING 0x8A +/*------------------- 0x8B */ +/*------------------- 0x8C */ +#define IAR_PMC_HP_TRIM 0x8D +#define IAR_VREGA_TRIM 0x8E +/*------------------- 0x8F */ +/*------------------- 0x90 */ +#define IAR_VCO_CTRL1 0x91 +#define IAR_VCO_CTRL2 0x92 +/*------------------- 0x93 */ +/*------------------- 0x94 */ +#define IAR_ANA_SPARE_OUT1 0x95 +#define IAR_ANA_SPARE_OUT2 0x96 +#define IAR_ANA_SPARE_IN 0x97 +#define IAR_MISCELLANEOUS 0x98 +/*------------------- 0x99 */ +#define IAR_SEQ_MGR_OVRD0 0x9A +#define IAR_SEQ_MGR_OVRD1 0x9B +#define IAR_SEQ_MGR_OVRD2 0x9C +#define IAR_SEQ_MGR_OVRD3 0x9D +#define IAR_SEQ_MGR_OVRD4 0x9E +#define IAR_SEQ_MGR_OVRD5 0x9F +#define IAR_SEQ_MGR_OVRD6 0xA0 +#define IAR_SEQ_MGR_OVRD7 0xA1 +/*------------------- 0xA2 */ +#define IAR_TESTMODE_CTRL 0xA3 +#define IAR_DTM_CTRL1 0xA4 +#define IAR_DTM_CTRL2 0xA5 +#define IAR_ATM_CTRL1 0xA6 +#define IAR_ATM_CTRL2 0xA7 +#define IAR_ATM_CTRL3 0xA8 +/*------------------- 0xA9 */ +#define IAR_LIM_FE_TEST_CTRL 0xAA +#define IAR_CHF_TEST_CTRL 0xAB +#define IAR_VCO_TEST_CTRL 0xAC +#define IAR_PLL_TEST_CTRL 0xAD +#define IAR_PA_TEST_CTRL 0xAE +#define IAR_PMC_TEST_CTRL 0xAF +#define IAR_SCAN_DTM_PROTECT_1 0xFE +#define IAR_SCAN_DTM_PROTECT_0 0xFF + +/* IRQSTS1 bits */ +#define DAR_IRQSTS1_RX_FRM_PEND BIT(7) +#define DAR_IRQSTS1_PLL_UNLOCK_IRQ BIT(6) +#define DAR_IRQSTS1_FILTERFAIL_IRQ BIT(5) +#define DAR_IRQSTS1_RXWTRMRKIRQ BIT(4) +#define DAR_IRQSTS1_CCAIRQ BIT(3) +#define DAR_IRQSTS1_RXIRQ BIT(2) +#define DAR_IRQSTS1_TXIRQ BIT(1) +#define DAR_IRQSTS1_SEQIRQ BIT(0) + +/* IRQSTS2 bits */ +#define DAR_IRQSTS2_CRCVALID BIT(7) +#define DAR_IRQSTS2_CCA BIT(6) +#define DAR_IRQSTS2_SRCADDR BIT(5) +#define DAR_IRQSTS2_PI BIT(4) +#define DAR_IRQSTS2_TMRSTATUS BIT(3) +#define DAR_IRQSTS2_ASM_IRQ BIT(2) +#define DAR_IRQSTS2_PB_ERR_IRQ BIT(1) +#define DAR_IRQSTS2_WAKE_IRQ BIT(0) + +/* IRQSTS3 bits */ +#define DAR_IRQSTS3_TMR4MSK BIT(7) +#define DAR_IRQSTS3_TMR3MSK BIT(6) +#define DAR_IRQSTS3_TMR2MSK BIT(5) +#define DAR_IRQSTS3_TMR1MSK BIT(4) +#define DAR_IRQSTS3_TMR4IRQ BIT(3) +#define DAR_IRQSTS3_TMR3IRQ BIT(2) +#define DAR_IRQSTS3_TMR2IRQ BIT(1) +#define DAR_IRQSTS3_TMR1IRQ BIT(0) + +/* PHY_CTRL1 bits */ +#define DAR_PHY_CTRL1_TMRTRIGEN BIT(7) +#define DAR_PHY_CTRL1_SLOTTED BIT(6) +#define DAR_PHY_CTRL1_CCABFRTX BIT(5) +#define DAR_PHY_CTRL1_CCABFRTX_SHIFT 5 +#define DAR_PHY_CTRL1_RXACKRQD BIT(4) +#define DAR_PHY_CTRL1_AUTOACK BIT(3) +#define DAR_PHY_CTRL1_XCVSEQ_MASK 0x07 + +/* PHY_CTRL2 bits */ +#define DAR_PHY_CTRL2_CRC_MSK BIT(7) +#define DAR_PHY_CTRL2_PLL_UNLOCK_MSK BIT(6) +#define DAR_PHY_CTRL2_FILTERFAIL_MSK BIT(5) +#define DAR_PHY_CTRL2_RX_WMRK_MSK BIT(4) +#define DAR_PHY_CTRL2_CCAMSK BIT(3) +#define DAR_PHY_CTRL2_RXMSK BIT(2) +#define DAR_PHY_CTRL2_TXMSK BIT(1) +#define DAR_PHY_CTRL2_SEQMSK BIT(0) + +/* PHY_CTRL3 bits */ +#define DAR_PHY_CTRL3_TMR4CMP_EN BIT(7) +#define DAR_PHY_CTRL3_TMR3CMP_EN BIT(6) +#define DAR_PHY_CTRL3_TMR2CMP_EN BIT(5) +#define DAR_PHY_CTRL3_TMR1CMP_EN BIT(4) +#define DAR_PHY_CTRL3_ASM_MSK BIT(2) +#define DAR_PHY_CTRL3_PB_ERR_MSK BIT(1) +#define DAR_PHY_CTRL3_WAKE_MSK BIT(0) + +/* RX_FRM_LEN bits */ +#define DAR_RX_FRAME_LENGTH_MASK (0x7F) + +/* PHY_CTRL4 bits */ +#define DAR_PHY_CTRL4_TRCV_MSK BIT(7) +#define DAR_PHY_CTRL4_TC3TMOUT BIT(6) +#define DAR_PHY_CTRL4_PANCORDNTR0 BIT(5) +#define DAR_PHY_CTRL4_CCATYPE (3) +#define DAR_PHY_CTRL4_CCATYPE_SHIFT (3) +#define DAR_PHY_CTRL4_CCATYPE_MASK (0x18) +#define DAR_PHY_CTRL4_TMRLOAD BIT(2) +#define DAR_PHY_CTRL4_PROMISCUOUS BIT(1) +#define DAR_PHY_CTRL4_TC2PRIME_EN BIT(0) + +/* SRC_CTRL bits */ +#define DAR_SRC_CTRL_INDEX (0x0F) +#define DAR_SRC_CTRL_INDEX_SHIFT (4) +#define DAR_SRC_CTRL_ACK_FRM_PND BIT(3) +#define DAR_SRC_CTRL_SRCADDR_EN BIT(2) +#define DAR_SRC_CTRL_INDEX_EN BIT(1) +#define DAR_SRC_CTRL_INDEX_DISABLE BIT(0) + +/* DAR_ASM_CTRL1 bits */ +#define DAR_ASM_CTRL1_CLEAR BIT(7) +#define DAR_ASM_CTRL1_START BIT(6) +#define DAR_ASM_CTRL1_SELFTST BIT(5) +#define DAR_ASM_CTRL1_CTR BIT(4) +#define DAR_ASM_CTRL1_CBC BIT(3) +#define DAR_ASM_CTRL1_AES BIT(2) +#define DAR_ASM_CTRL1_LOAD_MAC BIT(1) + +/* DAR_ASM_CTRL2 bits */ +#define DAR_ASM_CTRL2_DATA_REG_TYPE_SEL (7) +#define DAR_ASM_CTRL2_DATA_REG_TYPE_SEL_SHIFT (5) +#define DAR_ASM_CTRL2_TSTPAS BIT(1) + +/* DAR_CLK_OUT_CTRL bits */ +#define DAR_CLK_OUT_CTRL_EXTEND BIT(7) +#define DAR_CLK_OUT_CTRL_HIZ BIT(6) +#define DAR_CLK_OUT_CTRL_SR BIT(5) +#define DAR_CLK_OUT_CTRL_DS BIT(4) +#define DAR_CLK_OUT_CTRL_EN BIT(3) +#define DAR_CLK_OUT_CTRL_DIV (7) + +/* DAR_PWR_MODES bits */ +#define DAR_PWR_MODES_XTAL_READY BIT(5) +#define DAR_PWR_MODES_XTALEN BIT(4) +#define DAR_PWR_MODES_ASM_CLK_EN BIT(3) +#define DAR_PWR_MODES_AUTODOZE BIT(1) +#define DAR_PWR_MODES_PMC_MODE BIT(0) + +/* RX_FRAME_FILTER bits */ +#define IAR_RX_FRAME_FLT_FRM_VER (0xC0) +#define IAR_RX_FRAME_FLT_FRM_VER_SHIFT (6) +#define IAR_RX_FRAME_FLT_ACTIVE_PROMISCUOUS BIT(5) +#define IAR_RX_FRAME_FLT_NS_FT BIT(4) +#define IAR_RX_FRAME_FLT_CMD_FT BIT(3) +#define IAR_RX_FRAME_FLT_ACK_FT BIT(2) +#define IAR_RX_FRAME_FLT_DATA_FT BIT(1) +#define IAR_RX_FRAME_FLT_BEACON_FT BIT(0) + +/* DUAL_PAN_CTRL bits */ +#define IAR_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_MSK (0xF0) +#define IAR_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_SHIFT (4) +#define IAR_DUAL_PAN_CTRL_CURRENT_NETWORK BIT(3) +#define IAR_DUAL_PAN_CTRL_PANCORDNTR1 BIT(2) +#define IAR_DUAL_PAN_CTRL_DUAL_PAN_AUTO BIT(1) +#define IAR_DUAL_PAN_CTRL_ACTIVE_NETWORK BIT(0) + +/* DUAL_PAN_STS bits */ +#define IAR_DUAL_PAN_STS_RECD_ON_PAN1 BIT(7) +#define IAR_DUAL_PAN_STS_RECD_ON_PAN0 BIT(6) +#define IAR_DUAL_PAN_STS_DUAL_PAN_REMAIN (0x3F) + +/* CCA_CTRL bits */ +#define IAR_CCA_CTRL_AGC_FRZ_EN BIT(6) +#define IAR_CCA_CTRL_CONT_RSSI_EN BIT(5) +#define IAR_CCA_CTRL_LQI_RSSI_NOT_CORR BIT(4) +#define IAR_CCA_CTRL_CCA3_AND_NOT_OR BIT(3) +#define IAR_CCA_CTRL_POWER_COMP_EN_LQI BIT(2) +#define IAR_CCA_CTRL_POWER_COMP_EN_ED BIT(1) +#define IAR_CCA_CTRL_POWER_COMP_EN_CCA1 BIT(0) + +/* ANT_PAD_CTRL bits */ +#define IAR_ANT_PAD_CTRL_ANTX_POL (0x0F) +#define IAR_ANT_PAD_CTRL_ANTX_POL_SHIFT (4) +#define IAR_ANT_PAD_CTRL_ANTX_CTRLMODE BIT(3) +#define IAR_ANT_PAD_CTRL_ANTX_HZ BIT(2) +#define IAR_ANT_PAD_CTRL_ANTX_EN (3) + +/* MISC_PAD_CTRL bits */ +#define IAR_MISC_PAD_CTRL_MISO_HIZ_EN BIT(3) +#define IAR_MISC_PAD_CTRL_IRQ_B_OD BIT(2) +#define IAR_MISC_PAD_CTRL_NON_GPIO_DS BIT(1) +#define IAR_MISC_PAD_CTRL_ANTX_CURR (1) + +/* ANT_AGC_CTRL bits */ +#define IAR_ANT_AGC_CTRL_FAD_EN_SHIFT (0) +#define IAR_ANT_AGC_CTRL_FAD_EN_MASK (1) +#define IAR_ANT_AGC_CTRL_ANTX_SHIFT (1) +#define IAR_ANT_AGC_CTRL_ANTX_MASK BIT(AR_ANT_AGC_CTRL_ANTX_SHIFT) + +/* BSM_CTRL bits */ +#define BSM_CTRL_BSM_EN (1) + +/* SOFT_RESET bits */ +#define IAR_SOFT_RESET_SOG_RST BIT(7) +#define IAR_SOFT_RESET_REGS_RST BIT(4) +#define IAR_SOFT_RESET_PLL_RST BIT(3) +#define IAR_SOFT_RESET_TX_RST BIT(2) +#define IAR_SOFT_RESET_RX_RST BIT(1) +#define IAR_SOFT_RESET_SEQ_MGR_RST BIT(0) + +/* SEQ_MGR_CTRL bits */ +#define IAR_SEQ_MGR_CTRL_SEQ_STATE_CTRL (3) +#define IAR_SEQ_MGR_CTRL_SEQ_STATE_CTRL_SHIFT (6) +#define IAR_SEQ_MGR_CTRL_NO_RX_RECYCLE BIT(5) +#define IAR_SEQ_MGR_CTRL_LATCH_PREAMBLE BIT(4) +#define IAR_SEQ_MGR_CTRL_EVENT_TMR_DO_NOT_LATCH BIT(3) +#define IAR_SEQ_MGR_CTRL_CLR_NEW_SEQ_INHIBIT BIT(2) +#define IAR_SEQ_MGR_CTRL_PSM_LOCK_DIS BIT(1) +#define IAR_SEQ_MGR_CTRL_PLL_ABORT_OVRD BIT(0) + +/* SEQ_MGR_STS bits */ +#define IAR_SEQ_MGR_STS_TMR2_SEQ_TRIG_ARMED BIT(7) +#define IAR_SEQ_MGR_STS_RX_MODE BIT(6) +#define IAR_SEQ_MGR_STS_RX_TIMEOUT_PENDING BIT(5) +#define IAR_SEQ_MGR_STS_NEW_SEQ_INHIBIT BIT(4) +#define IAR_SEQ_MGR_STS_SEQ_IDLE BIT(3) +#define IAR_SEQ_MGR_STS_XCVSEQ_ACTUAL (7) + +/* ABORT_STS bits */ +#define IAR_ABORT_STS_PLL_ABORTED BIT(2) +#define IAR_ABORT_STS_TC3_ABORTED BIT(1) +#define IAR_ABORT_STS_SW_ABORTED BIT(0) + +/* IAR_FILTERFAIL_CODE2 bits */ +#define IAR_FILTERFAIL_CODE2_PAN_SEL BIT(7) +#define IAR_FILTERFAIL_CODE2_9_8 (3) + +/* PHY_STS bits */ +#define IAR_PHY_STS_PLL_UNLOCK BIT(7) +#define IAR_PHY_STS_PLL_LOCK_ERR BIT(6) +#define IAR_PHY_STS_PLL_LOCK BIT(5) +#define IAR_PHY_STS_CRCVALID BIT(3) +#define IAR_PHY_STS_FILTERFAIL_FLAG_SEL BIT(2) +#define IAR_PHY_STS_SFD_DET BIT(1) +#define IAR_PHY_STS_PREAMBLE_DET BIT(0) + +/* TESTMODE_CTRL bits */ +#define IAR_TEST_MODE_CTRL_HOT_ANT BIT(4) +#define IAR_TEST_MODE_CTRL_IDEAL_RSSI_EN BIT(3) +#define IAR_TEST_MODE_CTRL_IDEAL_PFC_EN BIT(2) +#define IAR_TEST_MODE_CTRL_CONTINUOUS_EN BIT(1) +#define IAR_TEST_MODE_CTRL_FPGA_EN BIT(0) + +/* DTM_CTRL1 bits */ +#define IAR_DTM_CTRL1_ATM_LOCKED BIT(7) +#define IAR_DTM_CTRL1_DTM_EN BIT(6) +#define IAR_DTM_CTRL1_PAGE5 BIT(5) +#define IAR_DTM_CTRL1_PAGE4 BIT(4) +#define IAR_DTM_CTRL1_PAGE3 BIT(3) +#define IAR_DTM_CTRL1_PAGE2 BIT(2) +#define IAR_DTM_CTRL1_PAGE1 BIT(1) +#define IAR_DTM_CTRL1_PAGE0 BIT(0) + +/* TX_MODE_CTRL */ +#define IAR_TX_MODE_CTRL_TX_INV BIT(4) +#define IAR_TX_MODE_CTRL_BT_EN BIT(3) +#define IAR_TX_MODE_CTRL_DTS2 BIT(2) +#define IAR_TX_MODE_CTRL_DTS1 BIT(1) +#define IAR_TX_MODE_CTRL_DTS0 BIT(0) + +#define TX_MODE_CTRL_DTS_MASK (7) + +#endif /* _MCR20A_H */ diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 67c91ceda979..d05b902c925b 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -1024,6 +1024,7 @@ static struct pernet_operations ipvlan_net_ops = { .id = &ipvlan_netid, .size = sizeof(struct ipvlan_netns), .exit = ipvlan_ns_exit, + .async = true, }; static int __init ipvlan_init_module(void) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 255a5def56e9..a393c1dff7dc 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -971,6 +971,7 @@ static struct pernet_operations ppp_net_ops = { .exit = ppp_exit_net, .id = &ppp_net_id, .size = sizeof(struct ppp_net), + .async = true, }; static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set) diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index bd89d1c559ce..c10e6181a2f0 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -1161,6 +1161,7 @@ static struct pernet_operations pppoe_net_ops = { .exit = pppoe_exit_net, .id = &pppoe_net_id, .size = sizeof(struct pppoe_net), + .async = true, }; static int __init pppoe_init(void) diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 9ce0182223a0..e459e601c57f 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1434,6 +1434,7 @@ static struct pernet_operations vrf_net_ops __net_initdata = { .init = vrf_netns_init, .id = &vrf_net_id, .size = sizeof(bool), + .async = true, }; static int __init vrf_init_module(void) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index fab7a4db249e..aa5f034d6ad1 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3752,6 +3752,7 @@ static struct pernet_operations vxlan_net_ops = { .exit_batch = vxlan_exit_batch_net, .id = &vxlan_net_id, .size = sizeof(struct vxlan_net), + .async = true, }; static int __init vxlan_init_module(void) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 9c36d614bf89..2dee4e03ff1c 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -709,6 +709,7 @@ static struct pernet_operations lockd_net_ops = { .exit = lockd_exit_net, .id = &lockd_net_id, .size = sizeof(struct lockd_net), + .async = true, }; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 7d893543cf3b..6c3083c992e5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -2122,6 +2122,7 @@ static struct pernet_operations nfs_net_ops = { .exit = nfs_net_exit, .id = &nfs_net_id, .size = sizeof(struct nfs_net), + .async = true, }; /* diff --git a/fs/nfs_common/grace.c b/fs/nfs_common/grace.c index 5be08f02a76b..8c743a405df6 100644 --- a/fs/nfs_common/grace.c +++ b/fs/nfs_common/grace.c @@ -118,6 +118,7 @@ static struct pernet_operations grace_net_ops = { .exit = grace_exit_net, .id = &grace_net_id, .size = sizeof(struct list_head), + .async = true, }; static int __init diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index bad01b14a4ad..bd0ed39f65fb 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -729,6 +729,7 @@ static struct pernet_operations vlan_net_ops = { .exit = vlan_exit_net, .id = &vlan_net_id, .size = sizeof(struct vlan_net), + .async = true, }; static int __init vlan_proto_init(void) diff --git a/net/bridge/br.c b/net/bridge/br.c index 6bf06e756df2..7770481a6506 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -188,6 +188,7 @@ static void __net_exit br_net_exit(struct net *net) static struct pernet_operations br_net_ops = { .exit = br_net_exit, + .async = true, }; static const struct stp_proto br_stp_proto = { diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index 27f1d4f2114a..484f54150525 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c @@ -967,6 +967,7 @@ static struct pernet_operations brnf_net_ops __read_mostly = { .exit = brnf_exit_net, .id = &brnf_net_id, .size = sizeof(struct brnf_net), + .async = true, }; static struct notifier_block brnf_notifier __read_mostly = { diff --git a/net/can/bcm.c b/net/can/bcm.c index ac5e5e34fee3..26730d39e048 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1717,6 +1717,7 @@ static void canbcm_pernet_exit(struct net *net) static struct pernet_operations canbcm_pernet_ops __read_mostly = { .init = canbcm_pernet_init, .exit = canbcm_pernet_exit, + .async = true, }; static int __init bcm_module_init(void) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 27a55236ad64..690e78c6af45 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -362,7 +362,7 @@ static void dec_net_namespaces(struct ucounts *ucounts) dec_ucount(ucounts, UCOUNT_NET_NAMESPACES); } -static struct kmem_cache *net_cachep; +static struct kmem_cache *net_cachep __ro_after_init; static struct workqueue_struct *netns_wq; static struct net *net_alloc(void) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1a7485a2cdfa..96d36b81a3a5 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -77,8 +77,8 @@ #include <linux/capability.h> #include <linux/user_namespace.h> -struct kmem_cache *skbuff_head_cache __read_mostly; -static struct kmem_cache *skbuff_fclone_cache __read_mostly; +struct kmem_cache *skbuff_head_cache __ro_after_init; +static struct kmem_cache *skbuff_fclone_cache __ro_after_init; int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; EXPORT_SYMBOL(sysctl_max_skb_frags); diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index 974765b7d92a..e4f305320519 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -104,6 +104,7 @@ static void lowpan_setup(struct net_device *ldev) /* We need an ipv6hdr as minimum len when calling xmit */ ldev->hard_header_len = sizeof(struct ipv6hdr); ldev->flags = IFF_BROADCAST | IFF_MULTICAST; + ldev->priv_flags |= IFF_NO_QUEUE; ldev->netdev_ops = &lowpan_netdev_ops; ldev->header_ops = &lowpan_header_ops; diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index cb7176cd4cd6..9104943c15ba 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -345,6 +345,7 @@ static void __net_exit cfg802154_pernet_exit(struct net *net) static struct pernet_operations cfg802154_pernet_ops = { .exit = cfg802154_pernet_exit, + .async = true, }; static int __init wpan_phy_class_init(void) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 5530cd6fdbc7..62243a8abf92 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -50,6 +50,7 @@ #define VERSION "0.409" +#include <linux/cache.h> #include <linux/uaccess.h> #include <linux/bitops.h> #include <linux/types.h> @@ -191,8 +192,8 @@ static size_t tnode_free_size; */ static const int sync_pages = 128; -static struct kmem_cache *fn_alias_kmem __read_mostly; -static struct kmem_cache *trie_leaf_kmem __read_mostly; +static struct kmem_cache *fn_alias_kmem __ro_after_init; +static struct kmem_cache *trie_leaf_kmem __ro_after_init; static inline struct tnode *tn_info(struct key_vector *kv) { diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 914d56928578..1f04bd91fc2e 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -6,6 +6,7 @@ * Authors: Andrey V. Savochkin <saw@msu.ru> */ +#include <linux/cache.h> #include <linux/module.h> #include <linux/types.h> #include <linux/slab.h> @@ -51,7 +52,7 @@ * daddr: unchangeable */ -static struct kmem_cache *peer_cachep __read_mostly; +static struct kmem_cache *peer_cachep __ro_after_init; void inet_peer_base_init(struct inet_peer_base *bp) { diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 45d97e9b2759..e496afa47709 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1044,6 +1044,7 @@ static struct pernet_operations ipgre_net_ops = { .exit_batch = ipgre_exit_batch_net, .id = &ipgre_net_id, .size = sizeof(struct ip_tunnel_net), + .async = true, }; static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], @@ -1623,6 +1624,7 @@ static struct pernet_operations ipgre_tap_net_ops = { .exit_batch = ipgre_tap_exit_batch_net, .id = &gre_tap_net_id, .size = sizeof(struct ip_tunnel_net), + .async = true, }; static int __net_init erspan_init_net(struct net *net) @@ -1641,6 +1643,7 @@ static struct pernet_operations erspan_net_ops = { .exit_batch = erspan_exit_batch_net, .id = &erspan_net_id, .size = sizeof(struct ip_tunnel_net), + .async = true, }; static int __init ipgre_init(void) diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 51b1669334fe..b10bf563afd9 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -454,6 +454,7 @@ static struct pernet_operations vti_net_ops = { .exit_batch = vti_exit_batch_net, .id = &vti_net_id, .size = sizeof(struct ip_tunnel_net), + .async = true, }; static int vti_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index c891235b4966..9c5a4d164f09 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -669,6 +669,7 @@ static struct pernet_operations ipip_net_ops = { .exit_batch = ipip_exit_batch_net, .id = &ipip_net_id, .size = sizeof(struct ip_tunnel_net), + .async = true, }; static int __init ipip_init(void) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 7c7ac9d32e77..591d1fc80a1f 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -28,6 +28,7 @@ #include <linux/uaccess.h> #include <linux/types.h> +#include <linux/cache.h> #include <linux/capability.h> #include <linux/errno.h> #include <linux/timer.h> @@ -96,7 +97,7 @@ static DEFINE_SPINLOCK(mfc_unres_lock); * In this case data path is free of exclusive locks at all. */ -static struct kmem_cache *mrt_cachep __read_mostly; +static struct kmem_cache *mrt_cachep __ro_after_init; static struct mr_table *ipmr_new_table(struct net *net, u32 id); static void ipmr_free_table(struct mr_table *mrt); diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 4b02ab39ebc5..08b3e48f44fc 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -840,6 +840,7 @@ static struct pernet_operations clusterip_net_ops = { .exit = clusterip_net_exit, .id = &clusterip_net_id, .size = sizeof(struct clusterip_net), + .async = true, }; static int __init clusterip_tg_init(void) diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index a0d3ad60a411..57244b62a4fc 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c @@ -118,6 +118,7 @@ static void __net_exit defrag4_net_exit(struct net *net) static struct pernet_operations defrag4_net_ops = { .exit = defrag4_net_exit, + .async = true, }; static int __init nf_defrag_init(void) diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c index 44c39c5f0638..e438699f000f 100644 --- a/net/ipv6/ila/ila_xlat.c +++ b/net/ipv6/ila/ila_xlat.c @@ -613,6 +613,7 @@ static struct pernet_operations ila_net_ops = { .exit = ila_exit_net, .id = &ila_net_id, .size = sizeof(struct ila_net), + .async = true, }; static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 3c353125546d..3026662a6413 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1517,6 +1517,7 @@ static struct pernet_operations ip6gre_net_ops = { .exit_batch = ip6gre_exit_batch_net, .id = &ip6gre_net_id, .size = sizeof(struct ip6gre_net), + .async = true, }; static int ip6gre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 4b15fe928278..869e2e6750f7 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -2250,6 +2250,7 @@ static struct pernet_operations ip6_tnl_net_ops = { .exit_batch = ip6_tnl_exit_batch_net, .id = &ip6_tnl_net_id, .size = sizeof(struct ip6_tnl_net), + .async = true, }; /** diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index fa3ae1cb50d3..c617ea17faa8 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -1148,6 +1148,7 @@ static struct pernet_operations vti6_net_ops = { .exit_batch = vti6_exit_batch_net, .id = &vti6_net_id, .size = sizeof(struct vti6_net), + .async = true, }; static struct xfrm6_protocol vti_esp6_protocol __read_mostly = { diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c index c87b48359e8f..32f98bc06900 100644 --- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c @@ -103,6 +103,7 @@ static void __net_exit defrag6_net_exit(struct net *net) static struct pernet_operations defrag6_net_ops = { .exit = defrag6_net_exit, + .async = true, }; static int __init nf_defrag_init(void) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 3a1775a62973..182db078f01e 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1878,6 +1878,7 @@ static struct pernet_operations sit_net_ops = { .exit_batch = sit_exit_batch_net, .id = &sit_net_id, .size = sizeof(struct sit_net), + .async = true, }; static void __exit sit_cleanup(void) diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index f85f0d7480ac..a9673619e0e9 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -353,6 +353,7 @@ static struct pernet_operations xfrm6_tunnel_net_ops = { .exit = xfrm6_tunnel_net_exit, .id = &xfrm6_tunnel_net_id, .size = sizeof(struct xfrm6_tunnel_net), + .async = true, }; static int __init xfrm6_tunnel_init(void) diff --git a/net/kcm/kcmproc.c b/net/kcm/kcmproc.c index 9d5649e4e8b7..2c1c8b3e4452 100644 --- a/net/kcm/kcmproc.c +++ b/net/kcm/kcmproc.c @@ -433,6 +433,7 @@ static void kcm_proc_exit_net(struct net *net) static struct pernet_operations kcm_net_ops = { .init = kcm_proc_init_net, .exit = kcm_proc_exit_net, + .async = true, }; int __init kcm_proc_init(void) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 435594648dac..a6cd0712e063 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -2015,6 +2015,7 @@ static struct pernet_operations kcm_net_ops = { .exit = kcm_exit_net, .id = &kcm_net_id, .size = sizeof(struct kcm_net), + .async = true, }; static int __init kcm_init(void) diff --git a/net/key/af_key.c b/net/key/af_key.c index 7e2e7188e7f4..3ac08ab26207 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3863,6 +3863,7 @@ static struct pernet_operations pfkey_net_ops = { .exit = pfkey_net_exit, .id = &pfkey_net_id, .size = sizeof(struct netns_pfkey), + .async = true, }; static void __exit ipsec_pfkey_exit(void) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 99a03c72db4f..0c4f49a6a0cb 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -1770,6 +1770,7 @@ static struct pernet_operations pppol2tp_net_ops = { .init = pppol2tp_init_net, .exit = pppol2tp_exit_net, .id = &pppol2tp_net_id, + .async = true, }; /***************************************************************************** diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index d625179de485..6a340c94c4b8 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -604,6 +604,7 @@ static void __net_exit __ip_vs_lblc_exit(struct net *net) { } static struct pernet_operations ip_vs_lblc_ops = { .init = __ip_vs_lblc_init, .exit = __ip_vs_lblc_exit, + .async = true, }; static int __init ip_vs_lblc_init(void) diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index 84c57b62a588..0627881128da 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -789,6 +789,7 @@ static void __net_exit __ip_vs_lblcr_exit(struct net *net) { } static struct pernet_operations ip_vs_lblcr_ops = { .init = __ip_vs_lblcr_init, .exit = __ip_vs_lblcr_exit, + .async = true, }; static int __init ip_vs_lblcr_init(void) diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c index 92139a087260..64b875e452ca 100644 --- a/net/netfilter/nf_synproxy_core.c +++ b/net/netfilter/nf_synproxy_core.c @@ -398,6 +398,7 @@ static struct pernet_operations synproxy_net_ops = { .exit = synproxy_net_exit, .id = &synproxy_net_id, .size = sizeof(struct synproxy_net), + .async = true, }; static int __init synproxy_core_init(void) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 66f5aca62a08..db2fe0911740 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -1345,6 +1345,7 @@ static struct pernet_operations hashlimit_net_ops = { .exit = hashlimit_net_exit, .id = &hashlimit_net_id, .size = sizeof(struct hashlimit_net), + .async = true, }; static int __init hashlimit_mt_init(void) diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 6d232d18faff..19efdb757944 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -687,6 +687,7 @@ static struct pernet_operations recent_net_ops = { .exit = recent_net_exit, .id = &recent_net_id, .size = sizeof(struct recent_net), + .async = true, }; static struct xt_match recent_mt_reg[] __read_mostly = { diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 77787512fc32..9454e8393793 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -342,6 +342,7 @@ static struct pernet_operations phonet_net_ops = { .exit = phonet_exit_net, .id = &phonet_net_id, .size = sizeof(struct phonet_net), + .async = true, }; /* Initialize Phonet devices list */ diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index cb3c5d403c88..da72e0cf2b1f 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -413,6 +413,7 @@ static struct pernet_operations bpf_net_ops = { .exit_batch = bpf_exit_net, .id = &bpf_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; static int __init bpf_init_module(void) diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c index e4b880fa51fe..371e5e4ab3e2 100644 --- a/net/sched/act_connmark.c +++ b/net/sched/act_connmark.c @@ -222,6 +222,7 @@ static struct pernet_operations connmark_net_ops = { .exit_batch = connmark_exit_net, .id = &connmark_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; static int __init connmark_init_module(void) diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index d5c2e528d150..1fb1f1f6a555 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -677,6 +677,7 @@ static struct pernet_operations csum_net_ops = { .exit_batch = csum_exit_net, .id = &csum_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_DESCRIPTION("Checksum updating actions"); diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index f072bcf33760..74563254e676 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -247,6 +247,7 @@ static struct pernet_operations gact_net_ops = { .exit_batch = gact_exit_net, .id = &gact_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index a5994cf0512b..555b1caeff72 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -870,6 +870,7 @@ static struct pernet_operations ife_net_ops = { .exit_batch = ife_exit_net, .id = &ife_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; static int __init ife_init_module(void) diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 9784629090ad..10866717f88e 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -349,6 +349,7 @@ static struct pernet_operations ipt_net_ops = { .exit_batch = ipt_exit_net, .id = &ipt_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; static int tcf_xt_walker(struct net *net, struct sk_buff *skb, @@ -399,6 +400,7 @@ static struct pernet_operations xt_net_ops = { .exit_batch = xt_exit_net, .id = &xt_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_AUTHOR("Jamal Hadi Salim(2002-13)"); diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index fd34015331ab..64c86579c3d9 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -353,6 +353,7 @@ static struct pernet_operations mirred_net_ops = { .exit_batch = mirred_exit_net, .id = &mirred_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_AUTHOR("Jamal Hadi Salim(2002)"); diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 4b5848b6c252..b1bc757f6491 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -323,6 +323,7 @@ static struct pernet_operations nat_net_ops = { .exit_batch = nat_exit_net, .id = &nat_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_DESCRIPTION("Stateless NAT actions"); diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 094303c27c5e..5e8cc8f63acd 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -465,6 +465,7 @@ static struct pernet_operations pedit_net_ops = { .exit_batch = pedit_exit_net, .id = &pedit_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); diff --git a/net/sched/act_police.c b/net/sched/act_police.c index ff55bd6c7db0..51fe4fe343f7 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -347,6 +347,7 @@ static struct pernet_operations police_net_ops = { .exit_batch = police_exit_net, .id = &police_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; static int __init police_init_module(void) diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index 9765145aaf40..238dfd27e995 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -248,6 +248,7 @@ static struct pernet_operations sample_net_ops = { .exit_batch = sample_exit_net, .id = &sample_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; static int __init sample_init_module(void) diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 8244e221fe4f..91816d73f3f3 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -216,6 +216,7 @@ static struct pernet_operations simp_net_ops = { .exit_batch = simp_exit_net, .id = &simp_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_AUTHOR("Jamal Hadi Salim(2005)"); diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index ddf69fc01bdf..7971510fe61b 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -253,6 +253,7 @@ static struct pernet_operations skbedit_net_ops = { .exit_batch = skbedit_exit_net, .id = &skbedit_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>"); diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index a406f191cb84..febec75f4f7a 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -278,6 +278,7 @@ static struct pernet_operations skbmod_net_ops = { .exit_batch = skbmod_exit_net, .id = &skbmod_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; MODULE_AUTHOR("Jamal Hadi Salim, <jhs@mojatatu.com>"); diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index 41ff9d0e5c62..9169b7e78ada 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -337,6 +337,7 @@ static struct pernet_operations tunnel_key_net_ops = { .exit_batch = tunnel_key_exit_net, .id = &tunnel_key_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; static int __init tunnel_key_init_module(void) diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index 71411a255f04..c2ee7fd51cc9 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@ -313,6 +313,7 @@ static struct pernet_operations vlan_net_ops = { .exit_batch = vlan_exit_net, .id = &vlan_net_id, .size = sizeof(struct tc_action_net), + .async = true, }; static int __init vlan_init_module(void) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 9d1a8bbf8152..19f9f421d5b7 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -1618,6 +1618,7 @@ static struct pernet_operations tcf_net_ops = { .exit = tcf_net_exit, .id = &tcf_net_id, .size = sizeof(struct tcf_net), + .async = true, }; static int __init tc_filter_init(void) diff --git a/net/socket.c b/net/socket.c index ab58e57c09ca..645d32b4872c 100644 --- a/net/socket.c +++ b/net/socket.c @@ -233,7 +233,7 @@ static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen, return __put_user(klen, ulen); } -static struct kmem_cache *sock_inode_cachep __read_mostly; +static struct kmem_cache *sock_inode_cachep __ro_after_init; static struct inode *sock_alloc_inode(struct super_block *sb) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8644d864e3c1..b4d7b6242a40 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6743,6 +6743,7 @@ static void __net_exit selinux_nf_unregister(struct net *net) static struct pernet_operations selinux_net_ops = { .init = selinux_nf_register, .exit = selinux_nf_unregister, + .async = true, }; static int __init selinux_nf_ip_init(void) diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c index e36d17835d4f..3f29c03162ca 100644 --- a/security/smack/smack_netfilter.c +++ b/security/smack/smack_netfilter.c @@ -89,6 +89,7 @@ static void __net_exit smack_nf_unregister(struct net *net) static struct pernet_operations smack_net_ops = { .init = smack_nf_register, .exit = smack_nf_unregister, + .async = true, }; static int __init smack_nf_ip_init(void) diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index d7c30d366935..229a038966e3 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -5,7 +5,7 @@ CFLAGS = -Wall -Wl,--no-as-needed -O2 -g CFLAGS += -I../../../../usr/include/ TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh -TEST_PROGS += fib_tests.sh +TEST_PROGS += fib_tests.sh fib-onlink-tests.sh TEST_GEN_FILES = socket TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa |