diff options
Diffstat (limited to 'drivers')
110 files changed, 3797 insertions, 2179 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 374696de796c..fbd54f0e32e8 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1428,8 +1428,10 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) else port->aggregator->is_individual = true; - port->aggregator->actor_admin_aggregator_key = port->actor_admin_port_key; - port->aggregator->actor_oper_aggregator_key = port->actor_oper_port_key; + port->aggregator->actor_admin_aggregator_key = + port->actor_admin_port_key; + port->aggregator->actor_oper_aggregator_key = + port->actor_oper_port_key; port->aggregator->partner_system = port->partner_oper.system; port->aggregator->partner_system_priority = @@ -1755,14 +1757,9 @@ static void ad_initialize_port(struct port *port, int lacp_fast) }; if (port) { - port->actor_port_number = 1; port->actor_port_priority = 0xff; - port->actor_system = null_mac_addr; - port->actor_system_priority = 0xffff; port->actor_port_aggregator_identifier = 0; port->ntt = false; - port->actor_admin_port_key = 1; - port->actor_oper_port_key = 1; port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY; port->actor_oper_port_state = AD_STATE_AGGREGATION | @@ -1784,8 +1781,6 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->sm_mux_state = 0; port->sm_mux_timer_counter = 0; port->sm_tx_state = 0; - port->sm_tx_timer_counter = 0; - port->slave = NULL; port->aggregator = NULL; port->next_port_in_aggregator = NULL; port->transaction_id = 0; @@ -1968,8 +1963,6 @@ void bond_3ad_bind_slave(struct slave *slave) * lacpdu's are sent in one second) */ port->sm_tx_timer_counter = ad_ticks_per_sec/AD_MAX_TX_IN_SECOND; - port->aggregator = NULL; - port->next_port_in_aggregator = NULL; __disable_port(port); @@ -2332,8 +2325,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) spin_lock_bh(&slave->bond->mode_lock); port->actor_admin_port_key &= ~AD_SPEED_KEY_MASKS; - port->actor_oper_port_key = port->actor_admin_port_key |= - (__get_link_speed(port) << 1); + port->actor_admin_port_key |= __get_link_speed(port) << 1; + port->actor_oper_port_key = port->actor_admin_port_key; netdev_dbg(slave->bond->dev, "Port %d changed speed\n", port->actor_port_number); /* there is no need to reselect a new aggregator, just signal the * state machines to reinitialize @@ -2365,8 +2358,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) spin_lock_bh(&slave->bond->mode_lock); port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS; - port->actor_oper_port_key = port->actor_admin_port_key |= - __get_duplex(port); + port->actor_admin_port_key |= __get_duplex(port); + port->actor_oper_port_key = port->actor_admin_port_key; netdev_dbg(slave->bond->dev, "Port %d slave %s changed duplex\n", port->actor_port_number, slave->dev->name); if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) @@ -2407,24 +2400,19 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) * on link up we are forcing recheck on the duplex and speed since * some of he adaptors(ce1000.lan) report. */ + port->actor_admin_port_key &= ~(AD_DUPLEX_KEY_MASKS|AD_SPEED_KEY_MASKS); if (link == BOND_LINK_UP) { port->is_enabled = true; - port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS; - port->actor_oper_port_key = port->actor_admin_port_key |= - __get_duplex(port); - port->actor_admin_port_key &= ~AD_SPEED_KEY_MASKS; - port->actor_oper_port_key = port->actor_admin_port_key |= - (__get_link_speed(port) << 1); - if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) + port->actor_admin_port_key |= + (__get_link_speed(port) << 1) | __get_duplex(port); + if (port->actor_admin_port_key & AD_DUPLEX_KEY_MASKS) port->sm_vars |= AD_PORT_LACP_ENABLED; } else { /* link has failed */ port->is_enabled = false; - port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS; - port->actor_oper_port_key = (port->actor_admin_port_key &= - ~AD_SPEED_KEY_MASKS); port->sm_vars &= ~AD_PORT_LACP_ENABLED; } + port->actor_oper_port_key = port->actor_admin_port_key; netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n", port->actor_port_number, link == BOND_LINK_UP ? "UP" : "DOWN"); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 80dd7a92f357..21d9497518fd 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -853,6 +853,22 @@ static int xgbe_set_mac_address(struct xgbe_prv_data *pdata, u8 *addr) return 0; } +static int xgbe_config_rx_mode(struct xgbe_prv_data *pdata) +{ + struct net_device *netdev = pdata->netdev; + unsigned int pr_mode, am_mode; + + pr_mode = ((netdev->flags & IFF_PROMISC) != 0); + am_mode = ((netdev->flags & IFF_ALLMULTI) != 0); + + xgbe_set_promiscuous_mode(pdata, pr_mode); + xgbe_set_all_multicast_mode(pdata, am_mode); + + xgbe_add_mac_addresses(pdata); + + return 0; +} + static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad, int mmd_reg) { @@ -1101,9 +1117,24 @@ static void xgbe_tx_desc_init(struct xgbe_channel *channel) DBGPR("<--tx_desc_init\n"); } -static void xgbe_rx_desc_reset(struct xgbe_ring_data *rdata) +static void xgbe_rx_desc_reset(struct xgbe_prv_data *pdata, + struct xgbe_ring_data *rdata, unsigned int index) { struct xgbe_ring_desc *rdesc = rdata->rdesc; + unsigned int rx_usecs = pdata->rx_usecs; + unsigned int rx_frames = pdata->rx_frames; + unsigned int inte; + + if (!rx_usecs && !rx_frames) { + /* No coalescing, interrupt for every descriptor */ + inte = 1; + } else { + /* Set interrupt based on Rx frame coalescing setting */ + if (rx_frames && !((index + 1) % rx_frames)) + inte = 1; + else + inte = 0; + } /* Reset the Rx descriptor * Set buffer 1 (lo) address to header dma address (lo) @@ -1117,8 +1148,7 @@ static void xgbe_rx_desc_reset(struct xgbe_ring_data *rdata) rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx.buf.dma)); rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx.buf.dma)); - XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, - rdata->interrupt ? 1 : 0); + XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, inte); /* Since the Rx DMA engine is likely running, make sure everything * is written to the descriptor(s) before setting the OWN bit @@ -1138,26 +1168,16 @@ static void xgbe_rx_desc_init(struct xgbe_channel *channel) struct xgbe_ring *ring = channel->rx_ring; struct xgbe_ring_data *rdata; unsigned int start_index = ring->cur; - unsigned int rx_coalesce, rx_frames; unsigned int i; DBGPR("-->rx_desc_init\n"); - rx_coalesce = (pdata->rx_riwt || pdata->rx_frames) ? 1 : 0; - rx_frames = pdata->rx_frames; - /* Initialize all descriptors */ for (i = 0; i < ring->rdesc_count; i++) { rdata = XGBE_GET_DESC_DATA(ring, i); - /* Set interrupt on completion bit as appropriate */ - if (rx_coalesce && (!rx_frames || ((i + 1) % rx_frames))) - rdata->interrupt = 0; - else - rdata->interrupt = 1; - /* Initialize Rx descriptor */ - xgbe_rx_desc_reset(rdata); + xgbe_rx_desc_reset(pdata, rdata, i); } /* Update the total number of Rx descriptors */ @@ -2804,6 +2824,7 @@ static int xgbe_init(struct xgbe_prv_data *pdata) * Initialize MAC related features */ xgbe_config_mac_address(pdata); + xgbe_config_rx_mode(pdata); xgbe_config_jumbo_enable(pdata); xgbe_config_flow_control(pdata); xgbe_config_mac_speed(pdata); @@ -2823,10 +2844,8 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) hw_if->tx_complete = xgbe_tx_complete; - hw_if->set_promiscuous_mode = xgbe_set_promiscuous_mode; - hw_if->set_all_multicast_mode = xgbe_set_all_multicast_mode; - hw_if->add_mac_addresses = xgbe_add_mac_addresses; hw_if->set_mac_address = xgbe_set_mac_address; + hw_if->config_rx_mode = xgbe_config_rx_mode; hw_if->enable_rx_csum = xgbe_enable_rx_csum; hw_if->disable_rx_csum = xgbe_disable_rx_csum; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 347fe2419a18..db84ddcfec84 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -129,7 +129,6 @@ static int xgbe_one_poll(struct napi_struct *, int); static int xgbe_all_poll(struct napi_struct *, int); -static void xgbe_set_rx_mode(struct net_device *); static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) { @@ -952,8 +951,6 @@ static int xgbe_start(struct xgbe_prv_data *pdata) DBGPR("-->xgbe_start\n"); - xgbe_set_rx_mode(netdev); - hw_if->init(pdata); phy_start(pdata->phydev); @@ -1533,17 +1530,10 @@ static void xgbe_set_rx_mode(struct net_device *netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; - unsigned int pr_mode, am_mode; DBGPR("-->xgbe_set_rx_mode\n"); - pr_mode = ((netdev->flags & IFF_PROMISC) != 0); - am_mode = ((netdev->flags & IFF_ALLMULTI) != 0); - - hw_if->set_promiscuous_mode(pdata, pr_mode); - hw_if->set_all_multicast_mode(pdata, am_mode); - - hw_if->add_mac_addresses(pdata); + hw_if->config_rx_mode(pdata); DBGPR("<--xgbe_set_rx_mode\n"); } @@ -1610,6 +1600,14 @@ static int xgbe_change_mtu(struct net_device *netdev, int mtu) return 0; } +static void xgbe_tx_timeout(struct net_device *netdev) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + + netdev_warn(netdev, "tx timeout, device restarting\n"); + schedule_work(&pdata->restart_work); +} + static struct rtnl_link_stats64 *xgbe_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *s) { @@ -1774,6 +1772,7 @@ static const struct net_device_ops xgbe_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = xgbe_ioctl, .ndo_change_mtu = xgbe_change_mtu, + .ndo_tx_timeout = xgbe_tx_timeout, .ndo_get_stats64 = xgbe_get_stats64, .ndo_vlan_rx_add_vid = xgbe_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = xgbe_vlan_rx_kill_vid, @@ -1806,7 +1805,7 @@ static void xgbe_rx_refresh(struct xgbe_channel *channel) if (desc_if->map_rx_buffer(pdata, ring, rdata)) break; - hw_if->rx_desc_reset(rdata); + hw_if->rx_desc_reset(pdata, rdata, ring->dirty); ring->dirty++; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index b4f6eaaa08f0..5f149e8ee20f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -424,16 +424,6 @@ static int xgbe_set_coalesce(struct net_device *netdev, (ec->rate_sample_interval)) return -EOPNOTSUPP; - /* Can only change rx-frames when interface is down (see - * rx_descriptor_init in xgbe-dev.c) - */ - rx_frames = pdata->rx_frames; - if (rx_frames != ec->rx_max_coalesced_frames && netif_running(netdev)) { - netdev_alert(netdev, - "interface must be down to change rx-frames\n"); - return -EINVAL; - } - rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs); rx_usecs = ec->rx_coalesce_usecs; rx_frames = ec->rx_max_coalesced_frames; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 2e4c22d94a6b..714905384900 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -491,6 +491,9 @@ static int xgbe_probe(struct platform_device *pdev) netdev->priv_flags |= IFF_UNICAST_FLT; + /* Use default watchdog timeout */ + netdev->watchdog_timeo = 0; + xgbe_init_rx_coalesce(pdata); xgbe_init_tx_coalesce(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index dd742426eb04..e62dfa2deab6 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -325,8 +325,6 @@ struct xgbe_ring_data { struct xgbe_tx_ring_data tx; /* Tx-related data */ struct xgbe_rx_ring_data rx; /* Rx-related data */ - unsigned int interrupt; /* Interrupt indicator */ - unsigned int mapped_as_page; /* Incomplete receive save location. If the budget is exhausted @@ -497,10 +495,8 @@ struct xgbe_mmc_stats { struct xgbe_hw_if { int (*tx_complete)(struct xgbe_ring_desc *); - int (*set_promiscuous_mode)(struct xgbe_prv_data *, unsigned int); - int (*set_all_multicast_mode)(struct xgbe_prv_data *, unsigned int); - int (*add_mac_addresses)(struct xgbe_prv_data *); int (*set_mac_address)(struct xgbe_prv_data *, u8 *addr); + int (*config_rx_mode)(struct xgbe_prv_data *); int (*enable_rx_csum)(struct xgbe_prv_data *); int (*disable_rx_csum)(struct xgbe_prv_data *); @@ -536,8 +532,9 @@ struct xgbe_hw_if { int (*dev_read)(struct xgbe_channel *); void (*tx_desc_init)(struct xgbe_channel *); void (*rx_desc_init)(struct xgbe_channel *); - void (*rx_desc_reset)(struct xgbe_ring_data *); void (*tx_desc_reset)(struct xgbe_ring_data *); + void (*rx_desc_reset)(struct xgbe_prv_data *, struct xgbe_ring_data *, + unsigned int); int (*is_last_desc)(struct xgbe_ring_desc *); int (*is_context_desc)(struct xgbe_ring_desc *); void (*tx_start_xmit)(struct xgbe_channel *, struct xgbe_ring *); diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index d6aa602f168d..e4b5b057f417 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -422,7 +422,7 @@ static inline int add_one_rx_buf(void *va, unsigned int len, d->addr_lo = cpu_to_be32(mapping); d->addr_hi = cpu_to_be32((u64) mapping >> 32); - wmb(); + dma_wmb(); d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); return 0; @@ -433,7 +433,7 @@ static inline int add_one_rx_chunk(dma_addr_t mapping, struct rx_desc *d, { d->addr_lo = cpu_to_be32(mapping); d->addr_hi = cpu_to_be32((u64) mapping >> 32); - wmb(); + dma_wmb(); d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); return 0; @@ -579,7 +579,7 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, q->sdesc[q->pidx] = q->sdesc[idx]; to->addr_lo = from->addr_lo; /* already big endian */ to->addr_hi = from->addr_hi; /* likewise */ - wmb(); + dma_wmb(); to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen)); to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen)); @@ -1068,7 +1068,7 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, sd->eop = 1; wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | V_WR_SGLSFLT(flits)) | wr_hi; - wmb(); + dma_wmb(); wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) | V_WR_GEN(gen)) | wr_lo; wr_gen2(d, gen); @@ -1114,7 +1114,7 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, } sd->eop = 1; wrp->wr_hi |= htonl(F_WR_EOP); - wmb(); + dma_wmb(); wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; wr_gen2((struct tx_desc *)wp, ogen); WARN_ON(ndesc != 0); @@ -1184,7 +1184,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) | V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | F_WR_SOP | F_WR_EOP | compl); - wmb(); + dma_wmb(); cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) | V_WR_TID(q->token)); wr_gen2(d, gen); @@ -1342,7 +1342,7 @@ static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | V_WR_BCNTLFLT(len & 7)); - wmb(); + dma_wmb(); to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) | V_WR_LEN((len + 7) / 8)); wr_gen2(d, gen); @@ -2271,7 +2271,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, u32 len, flags; __be32 rss_hi, rss_lo; - rmb(); + dma_rmb(); eth = r->rss_hdr.opcode == CPL_RX_PKT; rss_hi = *(const __be32 *)r; rss_lo = r->rss_hdr.rss_hash_val; @@ -2488,7 +2488,7 @@ static int process_pure_responses(struct adapter *adap, struct sge_qset *qs, } if (!is_new_response(r, q)) break; - rmb(); + dma_rmb(); } while (is_pure_response(r)); if (sleeping) @@ -2523,7 +2523,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) if (!is_new_response(r, q)) return -1; - rmb(); + dma_rmb(); if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index 07d9b68a4da2..ace0ab98d0f1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o -cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o +cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 6c80eb2e61f4..524d11098c56 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -60,6 +60,11 @@ enum { }; enum { + T4_REGMAP_SIZE = (160 * 1024), + T5_REGMAP_SIZE = (332 * 1024), +}; + +enum { MEM_EDC0, MEM_EDC1, MEM_MC, @@ -374,6 +379,17 @@ enum { }; enum { + MAX_TXQ_ENTRIES = 16384, + MAX_CTRL_TXQ_ENTRIES = 1024, + MAX_RSPQ_ENTRIES = 16384, + MAX_RX_BUFFERS = 16384, + MIN_TXQ_ENTRIES = 32, + MIN_CTRL_TXQ_ENTRIES = 32, + MIN_RSPQ_ENTRIES = 128, + MIN_FL_ENTRIES = 16 +}; + +enum { INGQ_EXTRAS = 2, /* firmware event queue and */ /* forwarded interrupts */ MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES @@ -1000,6 +1016,30 @@ static inline bool cxgb_poll_busy_polling(struct sge_rspq *q) } #endif /* CONFIG_NET_RX_BUSY_POLL */ +/* Return a version number to identify the type of adapter. The scheme is: + * - bits 0..9: chip version + * - bits 10..15: chip revision + * - bits 16..23: register dump version + */ +static inline unsigned int mk_adap_vers(struct adapter *ap) +{ + return CHELSIO_CHIP_VERSION(ap->params.chip) | + (CHELSIO_CHIP_RELEASE(ap->params.chip) << 10) | (1 << 16); +} + +/* Return a queue's interrupt hold-off time in us. 0 means no timer. */ +static inline unsigned int qtimer_val(const struct adapter *adap, + const struct sge_rspq *q) +{ + unsigned int idx = q->intr_params >> 1; + + return idx < SGE_NTIMERS ? adap->sge.timer_val[idx] : 0; +} + +/* driver version & name used for ethtool_drvinfo */ +extern char cxgb4_driver_name[]; +extern const char cxgb4_driver_version[]; + void t4_os_portmod_changed(const struct adapter *adap, int port_id); void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); @@ -1029,6 +1069,10 @@ int t4_sge_init(struct adapter *adap); void t4_sge_start(struct adapter *adap); void t4_sge_stop(struct adapter *adap); int cxgb_busy_poll(struct napi_struct *napi); +int cxgb4_set_rspq_intr_params(struct sge_rspq *q, unsigned int us, + unsigned int cnt); +void cxgb4_set_ethtool_ops(struct net_device *netdev); +int cxgb4_write_rss(const struct port_info *pi, const u16 *queues); extern int dbfifo_int_thresh; #define for_each_port(adapter, iter) \ @@ -1117,6 +1161,9 @@ static inline int t4_memory_write(struct adapter *adap, int mtype, u32 addr, return t4_memory_rw(adap, 0, mtype, addr, len, buf, 0); } +unsigned int t4_get_regs_len(struct adapter *adapter); +void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size); + int t4_seeprom_wp(struct adapter *adapter, bool enable); int get_vpd_params(struct adapter *adapter, struct vpd_params *p); int t4_read_flash(struct adapter *adapter, unsigned int addr, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c new file mode 100644 index 000000000000..10d82b51d7ef --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -0,0 +1,915 @@ +/* + * Copyright (C) 2013-2015 Chelsio Communications. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#include <linux/firmware.h> +#include <linux/mdio.h> + +#include "cxgb4.h" +#include "t4_regs.h" +#include "t4fw_api.h" + +#define EEPROM_MAGIC 0x38E2F10C + +static u32 get_msglevel(struct net_device *dev) +{ + return netdev2adap(dev)->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ + netdev2adap(dev)->msg_enable = val; +} + +static const char stats_strings[][ETH_GSTRING_LEN] = { + "TxOctetsOK ", + "TxFramesOK ", + "TxBroadcastFrames ", + "TxMulticastFrames ", + "TxUnicastFrames ", + "TxErrorFrames ", + + "TxFrames64 ", + "TxFrames65To127 ", + "TxFrames128To255 ", + "TxFrames256To511 ", + "TxFrames512To1023 ", + "TxFrames1024To1518 ", + "TxFrames1519ToMax ", + + "TxFramesDropped ", + "TxPauseFrames ", + "TxPPP0Frames ", + "TxPPP1Frames ", + "TxPPP2Frames ", + "TxPPP3Frames ", + "TxPPP4Frames ", + "TxPPP5Frames ", + "TxPPP6Frames ", + "TxPPP7Frames ", + + "RxOctetsOK ", + "RxFramesOK ", + "RxBroadcastFrames ", + "RxMulticastFrames ", + "RxUnicastFrames ", + + "RxFramesTooLong ", + "RxJabberErrors ", + "RxFCSErrors ", + "RxLengthErrors ", + "RxSymbolErrors ", + "RxRuntFrames ", + + "RxFrames64 ", + "RxFrames65To127 ", + "RxFrames128To255 ", + "RxFrames256To511 ", + "RxFrames512To1023 ", + "RxFrames1024To1518 ", + "RxFrames1519ToMax ", + + "RxPauseFrames ", + "RxPPP0Frames ", + "RxPPP1Frames ", + "RxPPP2Frames ", + "RxPPP3Frames ", + "RxPPP4Frames ", + "RxPPP5Frames ", + "RxPPP6Frames ", + "RxPPP7Frames ", + + "RxBG0FramesDropped ", + "RxBG1FramesDropped ", + "RxBG2FramesDropped ", + "RxBG3FramesDropped ", + "RxBG0FramesTrunc ", + "RxBG1FramesTrunc ", + "RxBG2FramesTrunc ", + "RxBG3FramesTrunc ", + + "TSO ", + "TxCsumOffload ", + "RxCsumGood ", + "VLANextractions ", + "VLANinsertions ", + "GROpackets ", + "GROmerged ", + "WriteCoalSuccess ", + "WriteCoalFail ", +}; + +static int get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } +} + +static int get_regs_len(struct net_device *dev) +{ + struct adapter *adap = netdev2adap(dev); + + return t4_get_regs_len(adap); +} + +static int get_eeprom_len(struct net_device *dev) +{ + return EEPROMSIZE; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct adapter *adapter = netdev2adap(dev); + u32 exprom_vers; + + strlcpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); + strlcpy(info->version, cxgb4_driver_version, + sizeof(info->version)); + strlcpy(info->bus_info, pci_name(adapter->pdev), + sizeof(info->bus_info)); + + if (adapter->params.fw_vers) + snprintf(info->fw_version, sizeof(info->fw_version), + "%u.%u.%u.%u, TP %u.%u.%u.%u", + FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), + FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers), + FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers), + FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers), + FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers), + FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), + FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), + FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); + + if (!t4_get_exprom_version(adapter, &exprom_vers)) + snprintf(info->erom_version, sizeof(info->erom_version), + "%u.%u.%u.%u", + FW_HDR_FW_VER_MAJOR_G(exprom_vers), + FW_HDR_FW_VER_MINOR_G(exprom_vers), + FW_HDR_FW_VER_MICRO_G(exprom_vers), + FW_HDR_FW_VER_BUILD_G(exprom_vers)); +} + +static void get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, stats_strings, sizeof(stats_strings)); +} + +/* port stats maintained per queue of the port. They should be in the same + * order as in stats_strings above. + */ +struct queue_port_stats { + u64 tso; + u64 tx_csum; + u64 rx_csum; + u64 vlan_ex; + u64 vlan_ins; + u64 gro_pkts; + u64 gro_merged; +}; + +static void collect_sge_port_stats(const struct adapter *adap, + const struct port_info *p, + struct queue_port_stats *s) +{ + int i; + const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; + const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; + + memset(s, 0, sizeof(*s)); + for (i = 0; i < p->nqsets; i++, rx++, tx++) { + s->tso += tx->tso; + s->tx_csum += tx->tx_cso; + s->rx_csum += rx->stats.rx_cso; + s->vlan_ex += rx->stats.vlan_ex; + s->vlan_ins += tx->vlan_ins; + s->gro_pkts += rx->stats.lro_pkts; + s->gro_merged += rx->stats.lro_merged; + } +} + +static void get_stats(struct net_device *dev, struct ethtool_stats *stats, + u64 *data) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + u32 val1, val2; + + t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data); + + data += sizeof(struct port_stats) / sizeof(u64); + collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); + data += sizeof(struct queue_port_stats) / sizeof(u64); + if (!is_t4(adapter->params.chip)) { + t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7)); + val1 = t4_read_reg(adapter, SGE_STAT_TOTAL_A); + val2 = t4_read_reg(adapter, SGE_STAT_MATCH_A); + *data = val1 - val2; + data++; + *data = val2; + data++; + } else { + memset(data, 0, 2 * sizeof(u64)); + *data += 2; + } +} + +static void get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct adapter *adap = netdev2adap(dev); + size_t buf_size; + + buf_size = t4_get_regs_len(adap); + regs->version = mk_adap_vers(adap); + t4_get_regs(adap, buf, buf_size); +} + +static int restart_autoneg(struct net_device *dev) +{ + struct port_info *p = netdev_priv(dev); + + if (!netif_running(dev)) + return -EAGAIN; + if (p->link_cfg.autoneg != AUTONEG_ENABLE) + return -EINVAL; + t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan); + return 0; +} + +static int identify_port(struct net_device *dev, + enum ethtool_phys_id_state state) +{ + unsigned int val; + struct adapter *adap = netdev2adap(dev); + + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; + + return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); +} + +static unsigned int from_fw_linkcaps(enum fw_port_type type, unsigned int caps) +{ + unsigned int v = 0; + + if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || + type == FW_PORT_TYPE_BT_XAUI) { + v |= SUPPORTED_TP; + if (caps & FW_PORT_CAP_SPEED_100M) + v |= SUPPORTED_100baseT_Full; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { + v |= SUPPORTED_Backplane; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseKX_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseKX4_Full; + } else if (type == FW_PORT_TYPE_KR) { + v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; + } else if (type == FW_PORT_TYPE_BP_AP) { + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; + } else if (type == FW_PORT_TYPE_BP4_AP) { + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | + SUPPORTED_10000baseKX4_Full; + } else if (type == FW_PORT_TYPE_FIBER_XFI || + type == FW_PORT_TYPE_FIBER_XAUI || + type == FW_PORT_TYPE_SFP || + type == FW_PORT_TYPE_QSFP_10G || + type == FW_PORT_TYPE_QSA) { + v |= SUPPORTED_FIBRE; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_BP40_BA || + type == FW_PORT_TYPE_QSFP) { + v |= SUPPORTED_40000baseSR4_Full; + v |= SUPPORTED_FIBRE; + } + + if (caps & FW_PORT_CAP_ANEG) + v |= SUPPORTED_Autoneg; + return v; +} + +static unsigned int to_fw_linkcaps(unsigned int caps) +{ + unsigned int v = 0; + + if (caps & ADVERTISED_100baseT_Full) + v |= FW_PORT_CAP_SPEED_100M; + if (caps & ADVERTISED_1000baseT_Full) + v |= FW_PORT_CAP_SPEED_1G; + if (caps & ADVERTISED_10000baseT_Full) + v |= FW_PORT_CAP_SPEED_10G; + if (caps & ADVERTISED_40000baseSR4_Full) + v |= FW_PORT_CAP_SPEED_40G; + return v; +} + +static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + const struct port_info *p = netdev_priv(dev); + + if (p->port_type == FW_PORT_TYPE_BT_SGMII || + p->port_type == FW_PORT_TYPE_BT_XFI || + p->port_type == FW_PORT_TYPE_BT_XAUI) { + cmd->port = PORT_TP; + } else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || + p->port_type == FW_PORT_TYPE_FIBER_XAUI) { + cmd->port = PORT_FIBRE; + } else if (p->port_type == FW_PORT_TYPE_SFP || + p->port_type == FW_PORT_TYPE_QSFP_10G || + p->port_type == FW_PORT_TYPE_QSA || + p->port_type == FW_PORT_TYPE_QSFP) { + if (p->mod_type == FW_PORT_MOD_TYPE_LR || + p->mod_type == FW_PORT_MOD_TYPE_SR || + p->mod_type == FW_PORT_MOD_TYPE_ER || + p->mod_type == FW_PORT_MOD_TYPE_LRM) + cmd->port = PORT_FIBRE; + else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || + p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) + cmd->port = PORT_DA; + else + cmd->port = PORT_OTHER; + } else { + cmd->port = PORT_OTHER; + } + + if (p->mdio_addr >= 0) { + cmd->phy_address = p->mdio_addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? + MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; + } else { + cmd->phy_address = 0; /* not really, but no better option */ + cmd->transceiver = XCVR_INTERNAL; + cmd->mdio_support = 0; + } + + cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); + cmd->advertising = from_fw_linkcaps(p->port_type, + p->link_cfg.advertising); + ethtool_cmd_speed_set(cmd, + netif_carrier_ok(dev) ? p->link_cfg.speed : 0); + cmd->duplex = DUPLEX_FULL; + cmd->autoneg = p->link_cfg.autoneg; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static unsigned int speed_to_caps(int speed) +{ + if (speed == 100) + return FW_PORT_CAP_SPEED_100M; + if (speed == 1000) + return FW_PORT_CAP_SPEED_1G; + if (speed == 10000) + return FW_PORT_CAP_SPEED_10G; + if (speed == 40000) + return FW_PORT_CAP_SPEED_40G; + return 0; +} + +static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + unsigned int cap; + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_cfg; + u32 speed = ethtool_cmd_speed(cmd); + + if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ + return -EINVAL; + + if (!(lc->supported & FW_PORT_CAP_ANEG)) { + /* PHY offers a single speed. See if that's what's + * being requested. + */ + if (cmd->autoneg == AUTONEG_DISABLE && + (lc->supported & speed_to_caps(speed))) + return 0; + return -EINVAL; + } + + if (cmd->autoneg == AUTONEG_DISABLE) { + cap = speed_to_caps(speed); + + if (!(lc->supported & cap) || + (speed == 1000) || + (speed == 10000) || + (speed == 40000)) + return -EINVAL; + lc->requested_speed = cap; + lc->advertising = 0; + } else { + cap = to_fw_linkcaps(cmd->advertising); + if (!(lc->supported & cap)) + return -EINVAL; + lc->requested_speed = 0; + lc->advertising = cap | FW_PORT_CAP_ANEG; + } + lc->autoneg = cmd->autoneg; + + if (netif_running(dev)) + return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, + lc); + return 0; +} + +static void get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + + epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; + epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; + epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; +} + +static int set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_cfg; + + if (epause->autoneg == AUTONEG_DISABLE) + lc->requested_fc = 0; + else if (lc->supported & FW_PORT_CAP_ANEG) + lc->requested_fc = PAUSE_AUTONEG; + else + return -EINVAL; + + if (epause->rx_pause) + lc->requested_fc |= PAUSE_RX; + if (epause->tx_pause) + lc->requested_fc |= PAUSE_TX; + if (netif_running(dev)) + return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, + lc); + return 0; +} + +static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + const struct port_info *pi = netdev_priv(dev); + const struct sge *s = &pi->adapter->sge; + + e->rx_max_pending = MAX_RX_BUFFERS; + e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; + e->rx_jumbo_max_pending = 0; + e->tx_max_pending = MAX_TXQ_ENTRIES; + + e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; + e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; + e->rx_jumbo_pending = 0; + e->tx_pending = s->ethtxq[pi->first_qset].q.size; +} + +static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + int i; + const struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct sge *s = &adapter->sge; + + if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || + e->tx_pending > MAX_TXQ_ENTRIES || + e->rx_mini_pending > MAX_RSPQ_ENTRIES || + e->rx_mini_pending < MIN_RSPQ_ENTRIES || + e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) + return -EINVAL; + + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + + for (i = 0; i < pi->nqsets; ++i) { + s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; + s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; + s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; + } + return 0; +} + +/** + * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete! + * @dev: the network device + * @us: the hold-off time in us, or 0 to disable timer + * @cnt: the hold-off packet count, or 0 to disable counter + * + * Set the RX interrupt hold-off parameters for a network device. + */ +static int set_rx_intr_params(struct net_device *dev, + unsigned int us, unsigned int cnt) +{ + int i, err; + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; + + for (i = 0; i < pi->nqsets; i++, q++) { + err = cxgb4_set_rspq_intr_params(&q->rspq, us, cnt); + if (err) + return err; + } + return 0; +} + +static int set_adaptive_rx_setting(struct net_device *dev, int adaptive_rx) +{ + int i; + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; + + for (i = 0; i < pi->nqsets; i++, q++) + q->rspq.adaptive_rx = adaptive_rx; + + return 0; +} + +static int get_adaptive_rx_setting(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; + + return q->rspq.adaptive_rx; +} + +static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + set_adaptive_rx_setting(dev, c->use_adaptive_rx_coalesce); + return set_rx_intr_params(dev, c->rx_coalesce_usecs, + c->rx_max_coalesced_frames); +} + +static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + const struct port_info *pi = netdev_priv(dev); + const struct adapter *adap = pi->adapter; + const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; + + c->rx_coalesce_usecs = qtimer_val(adap, rq); + c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN) ? + adap->sge.counter_val[rq->pktcnt_idx] : 0; + c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev); + return 0; +} + +/** + * eeprom_ptov - translate a physical EEPROM address to virtual + * @phys_addr: the physical EEPROM address + * @fn: the PCI function number + * @sz: size of function-specific area + * + * Translate a physical EEPROM address to virtual. The first 1K is + * accessed through virtual addresses starting at 31K, the rest is + * accessed through virtual addresses starting at 0. + * + * The mapping is as follows: + * [0..1K) -> [31K..32K) + * [1K..1K+A) -> [31K-A..31K) + * [1K+A..ES) -> [0..ES-A-1K) + * + * where A = @fn * @sz, and ES = EEPROM size. + */ +static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) +{ + fn *= sz; + if (phys_addr < 1024) + return phys_addr + (31 << 10); + if (phys_addr < 1024 + fn) + return 31744 - fn + phys_addr - 1024; + if (phys_addr < EEPROMSIZE) + return phys_addr - 1024 - fn; + return -EINVAL; +} + +/* The next two routines implement eeprom read/write from physical addresses. + */ +static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) +{ + int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); + + if (vaddr >= 0) + vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); + return vaddr < 0 ? vaddr : 0; +} + +static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) +{ + int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); + + if (vaddr >= 0) + vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); + return vaddr < 0 ? vaddr : 0; +} + +#define EEPROM_MAGIC 0x38E2F10C + +static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, + u8 *data) +{ + int i, err = 0; + struct adapter *adapter = netdev2adap(dev); + u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + e->magic = EEPROM_MAGIC; + for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) + err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); + + if (!err) + memcpy(data, buf + e->offset, e->len); + kfree(buf); + return err; +} + +static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 *data) +{ + u8 *buf; + int err = 0; + u32 aligned_offset, aligned_len, *p; + struct adapter *adapter = netdev2adap(dev); + + if (eeprom->magic != EEPROM_MAGIC) + return -EINVAL; + + aligned_offset = eeprom->offset & ~3; + aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; + + if (adapter->fn > 0) { + u32 start = 1024 + adapter->fn * EEPROMPFSIZE; + + if (aligned_offset < start || + aligned_offset + aligned_len > start + EEPROMPFSIZE) + return -EPERM; + } + + if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { + /* RMW possibly needed for first or last words. + */ + buf = kmalloc(aligned_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); + if (!err && aligned_len > 4) + err = eeprom_rd_phys(adapter, + aligned_offset + aligned_len - 4, + (u32 *)&buf[aligned_len - 4]); + if (err) + goto out; + memcpy(buf + (eeprom->offset & 3), data, eeprom->len); + } else { + buf = data; + } + + err = t4_seeprom_wp(adapter, false); + if (err) + goto out; + + for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { + err = eeprom_wr_phys(adapter, aligned_offset, *p); + aligned_offset += 4; + } + + if (!err) + err = t4_seeprom_wp(adapter, true); +out: + if (buf != data) + kfree(buf); + return err; +} + +static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) +{ + int ret; + const struct firmware *fw; + struct adapter *adap = netdev2adap(netdev); + unsigned int mbox = PCIE_FW_MASTER_M + 1; + + ef->data[sizeof(ef->data) - 1] = '\0'; + ret = request_firmware(&fw, ef->data, adap->pdev_dev); + if (ret < 0) + return ret; + + /* If the adapter has been fully initialized then we'll go ahead and + * try to get the firmware's cooperation in upgrading to the new + * firmware image otherwise we'll try to do the entire job from the + * host ... and we always "force" the operation in this path. + */ + if (adap->flags & FULL_INIT_DONE) + mbox = adap->mbox; + + ret = t4_fw_upgrade(adap, mbox, fw->data, fw->size, 1); + release_firmware(fw); + if (!ret) + dev_info(adap->pdev_dev, + "loaded firmware %s, reload cxgb4 driver\n", ef->data); + return ret; +} + +#define WOL_SUPPORTED (WAKE_BCAST | WAKE_MAGIC) +#define BCAST_CRC 0xa0ccc1a6 + +static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + wol->supported = WAKE_BCAST | WAKE_MAGIC; + wol->wolopts = netdev2adap(dev)->wol; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + int err = 0; + struct port_info *pi = netdev_priv(dev); + + if (wol->wolopts & ~WOL_SUPPORTED) + return -EINVAL; + t4_wol_magic_enable(pi->adapter, pi->tx_chan, + (wol->wolopts & WAKE_MAGIC) ? dev->dev_addr : NULL); + if (wol->wolopts & WAKE_BCAST) { + err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0xfe, ~0ULL, + ~0ULL, 0, false); + if (!err) + err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 1, + ~6ULL, ~0ULL, BCAST_CRC, true); + } else { + t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0, 0, 0, 0, false); + } + return err; +} + +static u32 get_rss_table_size(struct net_device *dev) +{ + const struct port_info *pi = netdev_priv(dev); + + return pi->rss_size; +} + +static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc) +{ + const struct port_info *pi = netdev_priv(dev); + unsigned int n = pi->rss_size; + + if (hfunc) + *hfunc = ETH_RSS_HASH_TOP; + if (!p) + return 0; + while (n--) + p[n] = pi->rss[n]; + return 0; +} + +static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key, + const u8 hfunc) +{ + unsigned int i; + struct port_info *pi = netdev_priv(dev); + + /* We require at least one supported parameter to be changed and no + * change in any of the unsupported parameters + */ + if (key || + (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) + return -EOPNOTSUPP; + if (!p) + return 0; + + for (i = 0; i < pi->rss_size; i++) + pi->rss[i] = p[i]; + if (pi->adapter->flags & FULL_INIT_DONE) + return cxgb4_write_rss(pi, pi->rss); + return 0; +} + +static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, + u32 *rules) +{ + const struct port_info *pi = netdev_priv(dev); + + switch (info->cmd) { + case ETHTOOL_GRXFH: { + unsigned int v = pi->rss_mode; + + info->data = 0; + switch (info->flow_type) { + case TCP_V4_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case UDP_V4_FLOW: + if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) && + (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case SCTP_V4_FLOW: + case AH_ESP_V4_FLOW: + case IPV4_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case TCP_V6_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case UDP_V6_FLOW: + if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) && + (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case SCTP_V6_FLOW: + case AH_ESP_V6_FLOW: + case IPV6_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + } + return 0; + } + case ETHTOOL_GRXRINGS: + info->data = pi->nqsets; + return 0; + } + return -EOPNOTSUPP; +} + +static const struct ethtool_ops cxgb_ethtool_ops = { + .get_settings = get_settings, + .set_settings = set_settings, + .get_drvinfo = get_drvinfo, + .get_msglevel = get_msglevel, + .set_msglevel = set_msglevel, + .get_ringparam = get_sge_param, + .set_ringparam = set_sge_param, + .get_coalesce = get_coalesce, + .set_coalesce = set_coalesce, + .get_eeprom_len = get_eeprom_len, + .get_eeprom = get_eeprom, + .set_eeprom = set_eeprom, + .get_pauseparam = get_pauseparam, + .set_pauseparam = set_pauseparam, + .get_link = ethtool_op_get_link, + .get_strings = get_strings, + .set_phys_id = identify_port, + .nway_reset = restart_autoneg, + .get_sset_count = get_sset_count, + .get_ethtool_stats = get_stats, + .get_regs_len = get_regs_len, + .get_regs = get_regs, + .get_wol = get_wol, + .set_wol = set_wol, + .get_rxnfc = get_rxnfc, + .get_rxfh_indir_size = get_rss_table_size, + .get_rxfh = get_rss_table, + .set_rxfh = set_rss_table, + .flash_device = set_flash, +}; + +void cxgb4_set_ethtool_ops(struct net_device *netdev) +{ + netdev->ethtool_ops = &cxgb_ethtool_ops; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 58c537f16763..24e10ea3d5ef 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -76,23 +76,15 @@ #include "clip_tbl.h" #include "l2t.h" +char cxgb4_driver_name[] = KBUILD_MODNAME; + #ifdef DRV_VERSION #undef DRV_VERSION #endif #define DRV_VERSION "2.0.0-ko" +const char cxgb4_driver_version[] = DRV_VERSION; #define DRV_DESC "Chelsio T4/T5 Network Driver" -enum { - MAX_TXQ_ENTRIES = 16384, - MAX_CTRL_TXQ_ENTRIES = 1024, - MAX_RSPQ_ENTRIES = 16384, - MAX_RX_BUFFERS = 16384, - MIN_TXQ_ENTRIES = 32, - MIN_CTRL_TXQ_ENTRIES = 32, - MIN_RSPQ_ENTRIES = 128, - MIN_FL_ENTRIES = 16 -}; - /* Host shadow copy of ingress filter entry. This is in host native format * and doesn't match the ordering or bit order, etc. of the hardware of the * firmware command. The use of bit-field structure elements is purely to @@ -857,14 +849,14 @@ static void free_msix_queue_irqs(struct adapter *adap) } /** - * write_rss - write the RSS table for a given port + * cxgb4_write_rss - write the RSS table for a given port * @pi: the port * @queues: array of queue indices for RSS * * Sets up the portion of the HW RSS table for the port's VI to distribute * packets to the Rx queues in @queues. */ -static int write_rss(const struct port_info *pi, const u16 *queues) +int cxgb4_write_rss(const struct port_info *pi, const u16 *queues) { u16 *rss; int i, err; @@ -897,7 +889,7 @@ static int setup_rss(struct adapter *adap) for_each_port(adap, i) { const struct port_info *pi = adap2pinfo(adap, i); - err = write_rss(pi, pi->rss); + err = cxgb4_write_rss(pi, pi->rss); if (err) return err; } @@ -1327,1192 +1319,6 @@ static inline int is_offload(const struct adapter *adap) return adap->params.offload; } -/* - * Implementation of ethtool operations. - */ - -static u32 get_msglevel(struct net_device *dev) -{ - return netdev2adap(dev)->msg_enable; -} - -static void set_msglevel(struct net_device *dev, u32 val) -{ - netdev2adap(dev)->msg_enable = val; -} - -static char stats_strings[][ETH_GSTRING_LEN] = { - "TxOctetsOK ", - "TxFramesOK ", - "TxBroadcastFrames ", - "TxMulticastFrames ", - "TxUnicastFrames ", - "TxErrorFrames ", - - "TxFrames64 ", - "TxFrames65To127 ", - "TxFrames128To255 ", - "TxFrames256To511 ", - "TxFrames512To1023 ", - "TxFrames1024To1518 ", - "TxFrames1519ToMax ", - - "TxFramesDropped ", - "TxPauseFrames ", - "TxPPP0Frames ", - "TxPPP1Frames ", - "TxPPP2Frames ", - "TxPPP3Frames ", - "TxPPP4Frames ", - "TxPPP5Frames ", - "TxPPP6Frames ", - "TxPPP7Frames ", - - "RxOctetsOK ", - "RxFramesOK ", - "RxBroadcastFrames ", - "RxMulticastFrames ", - "RxUnicastFrames ", - - "RxFramesTooLong ", - "RxJabberErrors ", - "RxFCSErrors ", - "RxLengthErrors ", - "RxSymbolErrors ", - "RxRuntFrames ", - - "RxFrames64 ", - "RxFrames65To127 ", - "RxFrames128To255 ", - "RxFrames256To511 ", - "RxFrames512To1023 ", - "RxFrames1024To1518 ", - "RxFrames1519ToMax ", - - "RxPauseFrames ", - "RxPPP0Frames ", - "RxPPP1Frames ", - "RxPPP2Frames ", - "RxPPP3Frames ", - "RxPPP4Frames ", - "RxPPP5Frames ", - "RxPPP6Frames ", - "RxPPP7Frames ", - - "RxBG0FramesDropped ", - "RxBG1FramesDropped ", - "RxBG2FramesDropped ", - "RxBG3FramesDropped ", - "RxBG0FramesTrunc ", - "RxBG1FramesTrunc ", - "RxBG2FramesTrunc ", - "RxBG3FramesTrunc ", - - "TSO ", - "TxCsumOffload ", - "RxCsumGood ", - "VLANextractions ", - "VLANinsertions ", - "GROpackets ", - "GROmerged ", - "WriteCoalSuccess ", - "WriteCoalFail ", -}; - -static int get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(stats_strings); - default: - return -EOPNOTSUPP; - } -} - -#define T4_REGMAP_SIZE (160 * 1024) -#define T5_REGMAP_SIZE (332 * 1024) - -static int get_regs_len(struct net_device *dev) -{ - struct adapter *adap = netdev2adap(dev); - if (is_t4(adap->params.chip)) - return T4_REGMAP_SIZE; - else - return T5_REGMAP_SIZE; -} - -static int get_eeprom_len(struct net_device *dev) -{ - return EEPROMSIZE; -} - -static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct adapter *adapter = netdev2adap(dev); - u32 exprom_vers; - - strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, pci_name(adapter->pdev), - sizeof(info->bus_info)); - - if (adapter->params.fw_vers) - snprintf(info->fw_version, sizeof(info->fw_version), - "%u.%u.%u.%u, TP %u.%u.%u.%u", - FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), - FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers), - FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers), - FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers), - FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers), - FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), - FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), - FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); - - if (!t4_get_exprom_version(adapter, &exprom_vers)) - snprintf(info->erom_version, sizeof(info->erom_version), - "%u.%u.%u.%u", - FW_HDR_FW_VER_MAJOR_G(exprom_vers), - FW_HDR_FW_VER_MINOR_G(exprom_vers), - FW_HDR_FW_VER_MICRO_G(exprom_vers), - FW_HDR_FW_VER_BUILD_G(exprom_vers)); -} - -static void get_strings(struct net_device *dev, u32 stringset, u8 *data) -{ - if (stringset == ETH_SS_STATS) - memcpy(data, stats_strings, sizeof(stats_strings)); -} - -/* - * port stats maintained per queue of the port. They should be in the same - * order as in stats_strings above. - */ -struct queue_port_stats { - u64 tso; - u64 tx_csum; - u64 rx_csum; - u64 vlan_ex; - u64 vlan_ins; - u64 gro_pkts; - u64 gro_merged; -}; - -static void collect_sge_port_stats(const struct adapter *adap, - const struct port_info *p, struct queue_port_stats *s) -{ - int i; - const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; - const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; - - memset(s, 0, sizeof(*s)); - for (i = 0; i < p->nqsets; i++, rx++, tx++) { - s->tso += tx->tso; - s->tx_csum += tx->tx_cso; - s->rx_csum += rx->stats.rx_cso; - s->vlan_ex += rx->stats.vlan_ex; - s->vlan_ins += tx->vlan_ins; - s->gro_pkts += rx->stats.lro_pkts; - s->gro_merged += rx->stats.lro_merged; - } -} - -static void get_stats(struct net_device *dev, struct ethtool_stats *stats, - u64 *data) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - u32 val1, val2; - - t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data); - - data += sizeof(struct port_stats) / sizeof(u64); - collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); - data += sizeof(struct queue_port_stats) / sizeof(u64); - if (!is_t4(adapter->params.chip)) { - t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7)); - val1 = t4_read_reg(adapter, SGE_STAT_TOTAL_A); - val2 = t4_read_reg(adapter, SGE_STAT_MATCH_A); - *data = val1 - val2; - data++; - *data = val2; - data++; - } else { - memset(data, 0, 2 * sizeof(u64)); - *data += 2; - } -} - -/* - * Return a version number to identify the type of adapter. The scheme is: - * - bits 0..9: chip version - * - bits 10..15: chip revision - * - bits 16..23: register dump version - */ -static inline unsigned int mk_adap_vers(const struct adapter *ap) -{ - return CHELSIO_CHIP_VERSION(ap->params.chip) | - (CHELSIO_CHIP_RELEASE(ap->params.chip) << 10) | (1 << 16); -} - -static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start, - unsigned int end) -{ - u32 *p = buf + start; - - for ( ; start <= end; start += sizeof(u32)) - *p++ = t4_read_reg(ap, start); -} - -static void get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *buf) -{ - static const unsigned int t4_reg_ranges[] = { - 0x1008, 0x1108, - 0x1180, 0x11b4, - 0x11fc, 0x123c, - 0x1300, 0x173c, - 0x1800, 0x18fc, - 0x3000, 0x30d8, - 0x30e0, 0x5924, - 0x5960, 0x59d4, - 0x5a00, 0x5af8, - 0x6000, 0x6098, - 0x6100, 0x6150, - 0x6200, 0x6208, - 0x6240, 0x6248, - 0x6280, 0x6338, - 0x6370, 0x638c, - 0x6400, 0x643c, - 0x6500, 0x6524, - 0x6a00, 0x6a38, - 0x6a60, 0x6a78, - 0x6b00, 0x6b84, - 0x6bf0, 0x6c84, - 0x6cf0, 0x6d84, - 0x6df0, 0x6e84, - 0x6ef0, 0x6f84, - 0x6ff0, 0x7084, - 0x70f0, 0x7184, - 0x71f0, 0x7284, - 0x72f0, 0x7384, - 0x73f0, 0x7450, - 0x7500, 0x7530, - 0x7600, 0x761c, - 0x7680, 0x76cc, - 0x7700, 0x7798, - 0x77c0, 0x77fc, - 0x7900, 0x79fc, - 0x7b00, 0x7c38, - 0x7d00, 0x7efc, - 0x8dc0, 0x8e1c, - 0x8e30, 0x8e78, - 0x8ea0, 0x8f6c, - 0x8fc0, 0x9074, - 0x90fc, 0x90fc, - 0x9400, 0x9458, - 0x9600, 0x96bc, - 0x9800, 0x9808, - 0x9820, 0x983c, - 0x9850, 0x9864, - 0x9c00, 0x9c6c, - 0x9c80, 0x9cec, - 0x9d00, 0x9d6c, - 0x9d80, 0x9dec, - 0x9e00, 0x9e6c, - 0x9e80, 0x9eec, - 0x9f00, 0x9f6c, - 0x9f80, 0x9fec, - 0xd004, 0xd03c, - 0xdfc0, 0xdfe0, - 0xe000, 0xea7c, - 0xf000, 0x11110, - 0x11118, 0x11190, - 0x19040, 0x1906c, - 0x19078, 0x19080, - 0x1908c, 0x19124, - 0x19150, 0x191b0, - 0x191d0, 0x191e8, - 0x19238, 0x1924c, - 0x193f8, 0x19474, - 0x19490, 0x194f8, - 0x19800, 0x19f30, - 0x1a000, 0x1a06c, - 0x1a0b0, 0x1a120, - 0x1a128, 0x1a138, - 0x1a190, 0x1a1c4, - 0x1a1fc, 0x1a1fc, - 0x1e040, 0x1e04c, - 0x1e284, 0x1e28c, - 0x1e2c0, 0x1e2c0, - 0x1e2e0, 0x1e2e0, - 0x1e300, 0x1e384, - 0x1e3c0, 0x1e3c8, - 0x1e440, 0x1e44c, - 0x1e684, 0x1e68c, - 0x1e6c0, 0x1e6c0, - 0x1e6e0, 0x1e6e0, - 0x1e700, 0x1e784, - 0x1e7c0, 0x1e7c8, - 0x1e840, 0x1e84c, - 0x1ea84, 0x1ea8c, - 0x1eac0, 0x1eac0, - 0x1eae0, 0x1eae0, - 0x1eb00, 0x1eb84, - 0x1ebc0, 0x1ebc8, - 0x1ec40, 0x1ec4c, - 0x1ee84, 0x1ee8c, - 0x1eec0, 0x1eec0, - 0x1eee0, 0x1eee0, - 0x1ef00, 0x1ef84, - 0x1efc0, 0x1efc8, - 0x1f040, 0x1f04c, - 0x1f284, 0x1f28c, - 0x1f2c0, 0x1f2c0, - 0x1f2e0, 0x1f2e0, - 0x1f300, 0x1f384, - 0x1f3c0, 0x1f3c8, - 0x1f440, 0x1f44c, - 0x1f684, 0x1f68c, - 0x1f6c0, 0x1f6c0, - 0x1f6e0, 0x1f6e0, - 0x1f700, 0x1f784, - 0x1f7c0, 0x1f7c8, - 0x1f840, 0x1f84c, - 0x1fa84, 0x1fa8c, - 0x1fac0, 0x1fac0, - 0x1fae0, 0x1fae0, - 0x1fb00, 0x1fb84, - 0x1fbc0, 0x1fbc8, - 0x1fc40, 0x1fc4c, - 0x1fe84, 0x1fe8c, - 0x1fec0, 0x1fec0, - 0x1fee0, 0x1fee0, - 0x1ff00, 0x1ff84, - 0x1ffc0, 0x1ffc8, - 0x20000, 0x2002c, - 0x20100, 0x2013c, - 0x20190, 0x201c8, - 0x20200, 0x20318, - 0x20400, 0x20528, - 0x20540, 0x20614, - 0x21000, 0x21040, - 0x2104c, 0x21060, - 0x210c0, 0x210ec, - 0x21200, 0x21268, - 0x21270, 0x21284, - 0x212fc, 0x21388, - 0x21400, 0x21404, - 0x21500, 0x21518, - 0x2152c, 0x2153c, - 0x21550, 0x21554, - 0x21600, 0x21600, - 0x21608, 0x21628, - 0x21630, 0x2163c, - 0x21700, 0x2171c, - 0x21780, 0x2178c, - 0x21800, 0x21c38, - 0x21c80, 0x21d7c, - 0x21e00, 0x21e04, - 0x22000, 0x2202c, - 0x22100, 0x2213c, - 0x22190, 0x221c8, - 0x22200, 0x22318, - 0x22400, 0x22528, - 0x22540, 0x22614, - 0x23000, 0x23040, - 0x2304c, 0x23060, - 0x230c0, 0x230ec, - 0x23200, 0x23268, - 0x23270, 0x23284, - 0x232fc, 0x23388, - 0x23400, 0x23404, - 0x23500, 0x23518, - 0x2352c, 0x2353c, - 0x23550, 0x23554, - 0x23600, 0x23600, - 0x23608, 0x23628, - 0x23630, 0x2363c, - 0x23700, 0x2371c, - 0x23780, 0x2378c, - 0x23800, 0x23c38, - 0x23c80, 0x23d7c, - 0x23e00, 0x23e04, - 0x24000, 0x2402c, - 0x24100, 0x2413c, - 0x24190, 0x241c8, - 0x24200, 0x24318, - 0x24400, 0x24528, - 0x24540, 0x24614, - 0x25000, 0x25040, - 0x2504c, 0x25060, - 0x250c0, 0x250ec, - 0x25200, 0x25268, - 0x25270, 0x25284, - 0x252fc, 0x25388, - 0x25400, 0x25404, - 0x25500, 0x25518, - 0x2552c, 0x2553c, - 0x25550, 0x25554, - 0x25600, 0x25600, - 0x25608, 0x25628, - 0x25630, 0x2563c, - 0x25700, 0x2571c, - 0x25780, 0x2578c, - 0x25800, 0x25c38, - 0x25c80, 0x25d7c, - 0x25e00, 0x25e04, - 0x26000, 0x2602c, - 0x26100, 0x2613c, - 0x26190, 0x261c8, - 0x26200, 0x26318, - 0x26400, 0x26528, - 0x26540, 0x26614, - 0x27000, 0x27040, - 0x2704c, 0x27060, - 0x270c0, 0x270ec, - 0x27200, 0x27268, - 0x27270, 0x27284, - 0x272fc, 0x27388, - 0x27400, 0x27404, - 0x27500, 0x27518, - 0x2752c, 0x2753c, - 0x27550, 0x27554, - 0x27600, 0x27600, - 0x27608, 0x27628, - 0x27630, 0x2763c, - 0x27700, 0x2771c, - 0x27780, 0x2778c, - 0x27800, 0x27c38, - 0x27c80, 0x27d7c, - 0x27e00, 0x27e04 - }; - - static const unsigned int t5_reg_ranges[] = { - 0x1008, 0x1148, - 0x1180, 0x11b4, - 0x11fc, 0x123c, - 0x1280, 0x173c, - 0x1800, 0x18fc, - 0x3000, 0x3028, - 0x3060, 0x30d8, - 0x30e0, 0x30fc, - 0x3140, 0x357c, - 0x35a8, 0x35cc, - 0x35ec, 0x35ec, - 0x3600, 0x5624, - 0x56cc, 0x575c, - 0x580c, 0x5814, - 0x5890, 0x58bc, - 0x5940, 0x59dc, - 0x59fc, 0x5a18, - 0x5a60, 0x5a9c, - 0x5b9c, 0x5bfc, - 0x6000, 0x6040, - 0x6058, 0x614c, - 0x7700, 0x7798, - 0x77c0, 0x78fc, - 0x7b00, 0x7c54, - 0x7d00, 0x7efc, - 0x8dc0, 0x8de0, - 0x8df8, 0x8e84, - 0x8ea0, 0x8f84, - 0x8fc0, 0x90f8, - 0x9400, 0x9470, - 0x9600, 0x96f4, - 0x9800, 0x9808, - 0x9820, 0x983c, - 0x9850, 0x9864, - 0x9c00, 0x9c6c, - 0x9c80, 0x9cec, - 0x9d00, 0x9d6c, - 0x9d80, 0x9dec, - 0x9e00, 0x9e6c, - 0x9e80, 0x9eec, - 0x9f00, 0x9f6c, - 0x9f80, 0xa020, - 0xd004, 0xd03c, - 0xdfc0, 0xdfe0, - 0xe000, 0x11088, - 0x1109c, 0x11110, - 0x11118, 0x1117c, - 0x11190, 0x11204, - 0x19040, 0x1906c, - 0x19078, 0x19080, - 0x1908c, 0x19124, - 0x19150, 0x191b0, - 0x191d0, 0x191e8, - 0x19238, 0x19290, - 0x193f8, 0x19474, - 0x19490, 0x194cc, - 0x194f0, 0x194f8, - 0x19c00, 0x19c60, - 0x19c94, 0x19e10, - 0x19e50, 0x19f34, - 0x19f40, 0x19f50, - 0x19f90, 0x19fe4, - 0x1a000, 0x1a06c, - 0x1a0b0, 0x1a120, - 0x1a128, 0x1a138, - 0x1a190, 0x1a1c4, - 0x1a1fc, 0x1a1fc, - 0x1e008, 0x1e00c, - 0x1e040, 0x1e04c, - 0x1e284, 0x1e290, - 0x1e2c0, 0x1e2c0, - 0x1e2e0, 0x1e2e0, - 0x1e300, 0x1e384, - 0x1e3c0, 0x1e3c8, - 0x1e408, 0x1e40c, - 0x1e440, 0x1e44c, - 0x1e684, 0x1e690, - 0x1e6c0, 0x1e6c0, - 0x1e6e0, 0x1e6e0, - 0x1e700, 0x1e784, - 0x1e7c0, 0x1e7c8, - 0x1e808, 0x1e80c, - 0x1e840, 0x1e84c, - 0x1ea84, 0x1ea90, - 0x1eac0, 0x1eac0, - 0x1eae0, 0x1eae0, - 0x1eb00, 0x1eb84, - 0x1ebc0, 0x1ebc8, - 0x1ec08, 0x1ec0c, - 0x1ec40, 0x1ec4c, - 0x1ee84, 0x1ee90, - 0x1eec0, 0x1eec0, - 0x1eee0, 0x1eee0, - 0x1ef00, 0x1ef84, - 0x1efc0, 0x1efc8, - 0x1f008, 0x1f00c, - 0x1f040, 0x1f04c, - 0x1f284, 0x1f290, - 0x1f2c0, 0x1f2c0, - 0x1f2e0, 0x1f2e0, - 0x1f300, 0x1f384, - 0x1f3c0, 0x1f3c8, - 0x1f408, 0x1f40c, - 0x1f440, 0x1f44c, - 0x1f684, 0x1f690, - 0x1f6c0, 0x1f6c0, - 0x1f6e0, 0x1f6e0, - 0x1f700, 0x1f784, - 0x1f7c0, 0x1f7c8, - 0x1f808, 0x1f80c, - 0x1f840, 0x1f84c, - 0x1fa84, 0x1fa90, - 0x1fac0, 0x1fac0, - 0x1fae0, 0x1fae0, - 0x1fb00, 0x1fb84, - 0x1fbc0, 0x1fbc8, - 0x1fc08, 0x1fc0c, - 0x1fc40, 0x1fc4c, - 0x1fe84, 0x1fe90, - 0x1fec0, 0x1fec0, - 0x1fee0, 0x1fee0, - 0x1ff00, 0x1ff84, - 0x1ffc0, 0x1ffc8, - 0x30000, 0x30030, - 0x30100, 0x30144, - 0x30190, 0x301d0, - 0x30200, 0x30318, - 0x30400, 0x3052c, - 0x30540, 0x3061c, - 0x30800, 0x30834, - 0x308c0, 0x30908, - 0x30910, 0x309ac, - 0x30a00, 0x30a04, - 0x30a0c, 0x30a2c, - 0x30a44, 0x30a50, - 0x30a74, 0x30c24, - 0x30d08, 0x30d14, - 0x30d1c, 0x30d20, - 0x30d3c, 0x30d50, - 0x31200, 0x3120c, - 0x31220, 0x31220, - 0x31240, 0x31240, - 0x31600, 0x31600, - 0x31608, 0x3160c, - 0x31a00, 0x31a1c, - 0x31e04, 0x31e20, - 0x31e38, 0x31e3c, - 0x31e80, 0x31e80, - 0x31e88, 0x31ea8, - 0x31eb0, 0x31eb4, - 0x31ec8, 0x31ed4, - 0x31fb8, 0x32004, - 0x32208, 0x3223c, - 0x32600, 0x32630, - 0x32a00, 0x32abc, - 0x32b00, 0x32b70, - 0x33000, 0x33048, - 0x33060, 0x3309c, - 0x330f0, 0x33148, - 0x33160, 0x3319c, - 0x331f0, 0x332e4, - 0x332f8, 0x333e4, - 0x333f8, 0x33448, - 0x33460, 0x3349c, - 0x334f0, 0x33548, - 0x33560, 0x3359c, - 0x335f0, 0x336e4, - 0x336f8, 0x337e4, - 0x337f8, 0x337fc, - 0x33814, 0x33814, - 0x3382c, 0x3382c, - 0x33880, 0x3388c, - 0x338e8, 0x338ec, - 0x33900, 0x33948, - 0x33960, 0x3399c, - 0x339f0, 0x33ae4, - 0x33af8, 0x33b10, - 0x33b28, 0x33b28, - 0x33b3c, 0x33b50, - 0x33bf0, 0x33c10, - 0x33c28, 0x33c28, - 0x33c3c, 0x33c50, - 0x33cf0, 0x33cfc, - 0x34000, 0x34030, - 0x34100, 0x34144, - 0x34190, 0x341d0, - 0x34200, 0x34318, - 0x34400, 0x3452c, - 0x34540, 0x3461c, - 0x34800, 0x34834, - 0x348c0, 0x34908, - 0x34910, 0x349ac, - 0x34a00, 0x34a04, - 0x34a0c, 0x34a2c, - 0x34a44, 0x34a50, - 0x34a74, 0x34c24, - 0x34d08, 0x34d14, - 0x34d1c, 0x34d20, - 0x34d3c, 0x34d50, - 0x35200, 0x3520c, - 0x35220, 0x35220, - 0x35240, 0x35240, - 0x35600, 0x35600, - 0x35608, 0x3560c, - 0x35a00, 0x35a1c, - 0x35e04, 0x35e20, - 0x35e38, 0x35e3c, - 0x35e80, 0x35e80, - 0x35e88, 0x35ea8, - 0x35eb0, 0x35eb4, - 0x35ec8, 0x35ed4, - 0x35fb8, 0x36004, - 0x36208, 0x3623c, - 0x36600, 0x36630, - 0x36a00, 0x36abc, - 0x36b00, 0x36b70, - 0x37000, 0x37048, - 0x37060, 0x3709c, - 0x370f0, 0x37148, - 0x37160, 0x3719c, - 0x371f0, 0x372e4, - 0x372f8, 0x373e4, - 0x373f8, 0x37448, - 0x37460, 0x3749c, - 0x374f0, 0x37548, - 0x37560, 0x3759c, - 0x375f0, 0x376e4, - 0x376f8, 0x377e4, - 0x377f8, 0x377fc, - 0x37814, 0x37814, - 0x3782c, 0x3782c, - 0x37880, 0x3788c, - 0x378e8, 0x378ec, - 0x37900, 0x37948, - 0x37960, 0x3799c, - 0x379f0, 0x37ae4, - 0x37af8, 0x37b10, - 0x37b28, 0x37b28, - 0x37b3c, 0x37b50, - 0x37bf0, 0x37c10, - 0x37c28, 0x37c28, - 0x37c3c, 0x37c50, - 0x37cf0, 0x37cfc, - 0x38000, 0x38030, - 0x38100, 0x38144, - 0x38190, 0x381d0, - 0x38200, 0x38318, - 0x38400, 0x3852c, - 0x38540, 0x3861c, - 0x38800, 0x38834, - 0x388c0, 0x38908, - 0x38910, 0x389ac, - 0x38a00, 0x38a04, - 0x38a0c, 0x38a2c, - 0x38a44, 0x38a50, - 0x38a74, 0x38c24, - 0x38d08, 0x38d14, - 0x38d1c, 0x38d20, - 0x38d3c, 0x38d50, - 0x39200, 0x3920c, - 0x39220, 0x39220, - 0x39240, 0x39240, - 0x39600, 0x39600, - 0x39608, 0x3960c, - 0x39a00, 0x39a1c, - 0x39e04, 0x39e20, - 0x39e38, 0x39e3c, - 0x39e80, 0x39e80, - 0x39e88, 0x39ea8, - 0x39eb0, 0x39eb4, - 0x39ec8, 0x39ed4, - 0x39fb8, 0x3a004, - 0x3a208, 0x3a23c, - 0x3a600, 0x3a630, - 0x3aa00, 0x3aabc, - 0x3ab00, 0x3ab70, - 0x3b000, 0x3b048, - 0x3b060, 0x3b09c, - 0x3b0f0, 0x3b148, - 0x3b160, 0x3b19c, - 0x3b1f0, 0x3b2e4, - 0x3b2f8, 0x3b3e4, - 0x3b3f8, 0x3b448, - 0x3b460, 0x3b49c, - 0x3b4f0, 0x3b548, - 0x3b560, 0x3b59c, - 0x3b5f0, 0x3b6e4, - 0x3b6f8, 0x3b7e4, - 0x3b7f8, 0x3b7fc, - 0x3b814, 0x3b814, - 0x3b82c, 0x3b82c, - 0x3b880, 0x3b88c, - 0x3b8e8, 0x3b8ec, - 0x3b900, 0x3b948, - 0x3b960, 0x3b99c, - 0x3b9f0, 0x3bae4, - 0x3baf8, 0x3bb10, - 0x3bb28, 0x3bb28, - 0x3bb3c, 0x3bb50, - 0x3bbf0, 0x3bc10, - 0x3bc28, 0x3bc28, - 0x3bc3c, 0x3bc50, - 0x3bcf0, 0x3bcfc, - 0x3c000, 0x3c030, - 0x3c100, 0x3c144, - 0x3c190, 0x3c1d0, - 0x3c200, 0x3c318, - 0x3c400, 0x3c52c, - 0x3c540, 0x3c61c, - 0x3c800, 0x3c834, - 0x3c8c0, 0x3c908, - 0x3c910, 0x3c9ac, - 0x3ca00, 0x3ca04, - 0x3ca0c, 0x3ca2c, - 0x3ca44, 0x3ca50, - 0x3ca74, 0x3cc24, - 0x3cd08, 0x3cd14, - 0x3cd1c, 0x3cd20, - 0x3cd3c, 0x3cd50, - 0x3d200, 0x3d20c, - 0x3d220, 0x3d220, - 0x3d240, 0x3d240, - 0x3d600, 0x3d600, - 0x3d608, 0x3d60c, - 0x3da00, 0x3da1c, - 0x3de04, 0x3de20, - 0x3de38, 0x3de3c, - 0x3de80, 0x3de80, - 0x3de88, 0x3dea8, - 0x3deb0, 0x3deb4, - 0x3dec8, 0x3ded4, - 0x3dfb8, 0x3e004, - 0x3e208, 0x3e23c, - 0x3e600, 0x3e630, - 0x3ea00, 0x3eabc, - 0x3eb00, 0x3eb70, - 0x3f000, 0x3f048, - 0x3f060, 0x3f09c, - 0x3f0f0, 0x3f148, - 0x3f160, 0x3f19c, - 0x3f1f0, 0x3f2e4, - 0x3f2f8, 0x3f3e4, - 0x3f3f8, 0x3f448, - 0x3f460, 0x3f49c, - 0x3f4f0, 0x3f548, - 0x3f560, 0x3f59c, - 0x3f5f0, 0x3f6e4, - 0x3f6f8, 0x3f7e4, - 0x3f7f8, 0x3f7fc, - 0x3f814, 0x3f814, - 0x3f82c, 0x3f82c, - 0x3f880, 0x3f88c, - 0x3f8e8, 0x3f8ec, - 0x3f900, 0x3f948, - 0x3f960, 0x3f99c, - 0x3f9f0, 0x3fae4, - 0x3faf8, 0x3fb10, - 0x3fb28, 0x3fb28, - 0x3fb3c, 0x3fb50, - 0x3fbf0, 0x3fc10, - 0x3fc28, 0x3fc28, - 0x3fc3c, 0x3fc50, - 0x3fcf0, 0x3fcfc, - 0x40000, 0x4000c, - 0x40040, 0x40068, - 0x40080, 0x40144, - 0x40180, 0x4018c, - 0x40200, 0x40298, - 0x402ac, 0x4033c, - 0x403f8, 0x403fc, - 0x41304, 0x413c4, - 0x41400, 0x4141c, - 0x41480, 0x414d0, - 0x44000, 0x44078, - 0x440c0, 0x44278, - 0x442c0, 0x44478, - 0x444c0, 0x44678, - 0x446c0, 0x44878, - 0x448c0, 0x449fc, - 0x45000, 0x45068, - 0x45080, 0x45084, - 0x450a0, 0x450b0, - 0x45200, 0x45268, - 0x45280, 0x45284, - 0x452a0, 0x452b0, - 0x460c0, 0x460e4, - 0x47000, 0x4708c, - 0x47200, 0x47250, - 0x47400, 0x47420, - 0x47600, 0x47618, - 0x47800, 0x47814, - 0x48000, 0x4800c, - 0x48040, 0x48068, - 0x48080, 0x48144, - 0x48180, 0x4818c, - 0x48200, 0x48298, - 0x482ac, 0x4833c, - 0x483f8, 0x483fc, - 0x49304, 0x493c4, - 0x49400, 0x4941c, - 0x49480, 0x494d0, - 0x4c000, 0x4c078, - 0x4c0c0, 0x4c278, - 0x4c2c0, 0x4c478, - 0x4c4c0, 0x4c678, - 0x4c6c0, 0x4c878, - 0x4c8c0, 0x4c9fc, - 0x4d000, 0x4d068, - 0x4d080, 0x4d084, - 0x4d0a0, 0x4d0b0, - 0x4d200, 0x4d268, - 0x4d280, 0x4d284, - 0x4d2a0, 0x4d2b0, - 0x4e0c0, 0x4e0e4, - 0x4f000, 0x4f08c, - 0x4f200, 0x4f250, - 0x4f400, 0x4f420, - 0x4f600, 0x4f618, - 0x4f800, 0x4f814, - 0x50000, 0x500cc, - 0x50400, 0x50400, - 0x50800, 0x508cc, - 0x50c00, 0x50c00, - 0x51000, 0x5101c, - 0x51300, 0x51308, - }; - - int i; - struct adapter *ap = netdev2adap(dev); - static const unsigned int *reg_ranges; - int arr_size = 0, buf_size = 0; - - if (is_t4(ap->params.chip)) { - reg_ranges = &t4_reg_ranges[0]; - arr_size = ARRAY_SIZE(t4_reg_ranges); - buf_size = T4_REGMAP_SIZE; - } else { - reg_ranges = &t5_reg_ranges[0]; - arr_size = ARRAY_SIZE(t5_reg_ranges); - buf_size = T5_REGMAP_SIZE; - } - - regs->version = mk_adap_vers(ap); - - memset(buf, 0, buf_size); - for (i = 0; i < arr_size; i += 2) - reg_block_dump(ap, buf, reg_ranges[i], reg_ranges[i + 1]); -} - -static int restart_autoneg(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - if (!netif_running(dev)) - return -EAGAIN; - if (p->link_cfg.autoneg != AUTONEG_ENABLE) - return -EINVAL; - t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan); - return 0; -} - -static int identify_port(struct net_device *dev, - enum ethtool_phys_id_state state) -{ - unsigned int val; - struct adapter *adap = netdev2adap(dev); - - if (state == ETHTOOL_ID_ACTIVE) - val = 0xffff; - else if (state == ETHTOOL_ID_INACTIVE) - val = 0; - else - return -EINVAL; - - return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); -} - -static unsigned int from_fw_linkcaps(enum fw_port_type type, unsigned int caps) -{ - unsigned int v = 0; - - if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || - type == FW_PORT_TYPE_BT_XAUI) { - v |= SUPPORTED_TP; - if (caps & FW_PORT_CAP_SPEED_100M) - v |= SUPPORTED_100baseT_Full; - if (caps & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseT_Full; - if (caps & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseT_Full; - } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { - v |= SUPPORTED_Backplane; - if (caps & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseKX_Full; - if (caps & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseKX4_Full; - } else if (type == FW_PORT_TYPE_KR) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; - else if (type == FW_PORT_TYPE_BP_AP) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | - SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; - else if (type == FW_PORT_TYPE_BP4_AP) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | - SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | - SUPPORTED_10000baseKX4_Full; - else if (type == FW_PORT_TYPE_FIBER_XFI || - type == FW_PORT_TYPE_FIBER_XAUI || - type == FW_PORT_TYPE_SFP || - type == FW_PORT_TYPE_QSFP_10G || - type == FW_PORT_TYPE_QSA) { - v |= SUPPORTED_FIBRE; - if (caps & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseT_Full; - if (caps & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseT_Full; - } else if (type == FW_PORT_TYPE_BP40_BA || - type == FW_PORT_TYPE_QSFP) { - v |= SUPPORTED_40000baseSR4_Full; - v |= SUPPORTED_FIBRE; - } - - if (caps & FW_PORT_CAP_ANEG) - v |= SUPPORTED_Autoneg; - return v; -} - -static unsigned int to_fw_linkcaps(unsigned int caps) -{ - unsigned int v = 0; - - if (caps & ADVERTISED_100baseT_Full) - v |= FW_PORT_CAP_SPEED_100M; - if (caps & ADVERTISED_1000baseT_Full) - v |= FW_PORT_CAP_SPEED_1G; - if (caps & ADVERTISED_10000baseT_Full) - v |= FW_PORT_CAP_SPEED_10G; - if (caps & ADVERTISED_40000baseSR4_Full) - v |= FW_PORT_CAP_SPEED_40G; - return v; -} - -static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - const struct port_info *p = netdev_priv(dev); - - if (p->port_type == FW_PORT_TYPE_BT_SGMII || - p->port_type == FW_PORT_TYPE_BT_XFI || - p->port_type == FW_PORT_TYPE_BT_XAUI) - cmd->port = PORT_TP; - else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || - p->port_type == FW_PORT_TYPE_FIBER_XAUI) - cmd->port = PORT_FIBRE; - else if (p->port_type == FW_PORT_TYPE_SFP || - p->port_type == FW_PORT_TYPE_QSFP_10G || - p->port_type == FW_PORT_TYPE_QSA || - p->port_type == FW_PORT_TYPE_QSFP) { - if (p->mod_type == FW_PORT_MOD_TYPE_LR || - p->mod_type == FW_PORT_MOD_TYPE_SR || - p->mod_type == FW_PORT_MOD_TYPE_ER || - p->mod_type == FW_PORT_MOD_TYPE_LRM) - cmd->port = PORT_FIBRE; - else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || - p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) - cmd->port = PORT_DA; - else - cmd->port = PORT_OTHER; - } else - cmd->port = PORT_OTHER; - - if (p->mdio_addr >= 0) { - cmd->phy_address = p->mdio_addr; - cmd->transceiver = XCVR_EXTERNAL; - cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? - MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; - } else { - cmd->phy_address = 0; /* not really, but no better option */ - cmd->transceiver = XCVR_INTERNAL; - cmd->mdio_support = 0; - } - - cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); - cmd->advertising = from_fw_linkcaps(p->port_type, - p->link_cfg.advertising); - ethtool_cmd_speed_set(cmd, - netif_carrier_ok(dev) ? p->link_cfg.speed : 0); - cmd->duplex = DUPLEX_FULL; - cmd->autoneg = p->link_cfg.autoneg; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - return 0; -} - -static unsigned int speed_to_caps(int speed) -{ - if (speed == 100) - return FW_PORT_CAP_SPEED_100M; - if (speed == 1000) - return FW_PORT_CAP_SPEED_1G; - if (speed == 10000) - return FW_PORT_CAP_SPEED_10G; - if (speed == 40000) - return FW_PORT_CAP_SPEED_40G; - return 0; -} - -static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - unsigned int cap; - struct port_info *p = netdev_priv(dev); - struct link_config *lc = &p->link_cfg; - u32 speed = ethtool_cmd_speed(cmd); - - if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ - return -EINVAL; - - if (!(lc->supported & FW_PORT_CAP_ANEG)) { - /* - * PHY offers a single speed. See if that's what's - * being requested. - */ - if (cmd->autoneg == AUTONEG_DISABLE && - (lc->supported & speed_to_caps(speed))) - return 0; - return -EINVAL; - } - - if (cmd->autoneg == AUTONEG_DISABLE) { - cap = speed_to_caps(speed); - - if (!(lc->supported & cap) || - (speed == 1000) || - (speed == 10000) || - (speed == 40000)) - return -EINVAL; - lc->requested_speed = cap; - lc->advertising = 0; - } else { - cap = to_fw_linkcaps(cmd->advertising); - if (!(lc->supported & cap)) - return -EINVAL; - lc->requested_speed = 0; - lc->advertising = cap | FW_PORT_CAP_ANEG; - } - lc->autoneg = cmd->autoneg; - - if (netif_running(dev)) - return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, - lc); - return 0; -} - -static void get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct port_info *p = netdev_priv(dev); - - epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; - epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; - epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; -} - -static int set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct port_info *p = netdev_priv(dev); - struct link_config *lc = &p->link_cfg; - - if (epause->autoneg == AUTONEG_DISABLE) - lc->requested_fc = 0; - else if (lc->supported & FW_PORT_CAP_ANEG) - lc->requested_fc = PAUSE_AUTONEG; - else - return -EINVAL; - - if (epause->rx_pause) - lc->requested_fc |= PAUSE_RX; - if (epause->tx_pause) - lc->requested_fc |= PAUSE_TX; - if (netif_running(dev)) - return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, - lc); - return 0; -} - -static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - const struct port_info *pi = netdev_priv(dev); - const struct sge *s = &pi->adapter->sge; - - e->rx_max_pending = MAX_RX_BUFFERS; - e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; - e->rx_jumbo_max_pending = 0; - e->tx_max_pending = MAX_TXQ_ENTRIES; - - e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; - e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; - e->rx_jumbo_pending = 0; - e->tx_pending = s->ethtxq[pi->first_qset].q.size; -} - -static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - int i; - const struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct sge *s = &adapter->sge; - - if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || - e->tx_pending > MAX_TXQ_ENTRIES || - e->rx_mini_pending > MAX_RSPQ_ENTRIES || - e->rx_mini_pending < MIN_RSPQ_ENTRIES || - e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) - return -EINVAL; - - if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; - - for (i = 0; i < pi->nqsets; ++i) { - s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; - s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; - s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; - } - return 0; -} - static int closest_timer(const struct sge *s, int time) { int i, delta, match = 0, min_delta = INT_MAX; @@ -2545,19 +1351,8 @@ static int closest_thres(const struct sge *s, int thres) return match; } -/* - * Return a queue's interrupt hold-off time in us. 0 means no timer. - */ -unsigned int qtimer_val(const struct adapter *adap, - const struct sge_rspq *q) -{ - unsigned int idx = q->intr_params >> 1; - - return idx < SGE_NTIMERS ? adap->sge.timer_val[idx] : 0; -} - /** - * set_rspq_intr_params - set a queue's interrupt holdoff parameters + * cxgb4_set_rspq_intr_params - set a queue's interrupt holdoff parameters * @q: the Rx queue * @us: the hold-off time in us, or 0 to disable timer * @cnt: the hold-off packet count, or 0 to disable counter @@ -2565,8 +1360,8 @@ unsigned int qtimer_val(const struct adapter *adap, * Sets an Rx queue's interrupt hold-off time and packet count. At least * one of the two needs to be enabled for the queue to generate interrupts. */ -static int set_rspq_intr_params(struct sge_rspq *q, - unsigned int us, unsigned int cnt) +int cxgb4_set_rspq_intr_params(struct sge_rspq *q, + unsigned int us, unsigned int cnt) { struct adapter *adap = q->adap; @@ -2597,259 +1392,6 @@ static int set_rspq_intr_params(struct sge_rspq *q, return 0; } -/** - * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete! - * @dev: the network device - * @us: the hold-off time in us, or 0 to disable timer - * @cnt: the hold-off packet count, or 0 to disable counter - * - * Set the RX interrupt hold-off parameters for a network device. - */ -static int set_rx_intr_params(struct net_device *dev, - unsigned int us, unsigned int cnt) -{ - int i, err; - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; - - for (i = 0; i < pi->nqsets; i++, q++) { - err = set_rspq_intr_params(&q->rspq, us, cnt); - if (err) - return err; - } - return 0; -} - -static int set_adaptive_rx_setting(struct net_device *dev, int adaptive_rx) -{ - int i; - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; - - for (i = 0; i < pi->nqsets; i++, q++) - q->rspq.adaptive_rx = adaptive_rx; - - return 0; -} - -static int get_adaptive_rx_setting(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; - - return q->rspq.adaptive_rx; -} - -static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - set_adaptive_rx_setting(dev, c->use_adaptive_rx_coalesce); - return set_rx_intr_params(dev, c->rx_coalesce_usecs, - c->rx_max_coalesced_frames); -} - -static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - const struct port_info *pi = netdev_priv(dev); - const struct adapter *adap = pi->adapter; - const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; - - c->rx_coalesce_usecs = qtimer_val(adap, rq); - c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN) ? - adap->sge.counter_val[rq->pktcnt_idx] : 0; - c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev); - return 0; -} - -/** - * eeprom_ptov - translate a physical EEPROM address to virtual - * @phys_addr: the physical EEPROM address - * @fn: the PCI function number - * @sz: size of function-specific area - * - * Translate a physical EEPROM address to virtual. The first 1K is - * accessed through virtual addresses starting at 31K, the rest is - * accessed through virtual addresses starting at 0. - * - * The mapping is as follows: - * [0..1K) -> [31K..32K) - * [1K..1K+A) -> [31K-A..31K) - * [1K+A..ES) -> [0..ES-A-1K) - * - * where A = @fn * @sz, and ES = EEPROM size. - */ -static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) -{ - fn *= sz; - if (phys_addr < 1024) - return phys_addr + (31 << 10); - if (phys_addr < 1024 + fn) - return 31744 - fn + phys_addr - 1024; - if (phys_addr < EEPROMSIZE) - return phys_addr - 1024 - fn; - return -EINVAL; -} - -/* - * The next two routines implement eeprom read/write from physical addresses. - */ -static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) -{ - int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); - - if (vaddr >= 0) - vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); - return vaddr < 0 ? vaddr : 0; -} - -static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) -{ - int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); - - if (vaddr >= 0) - vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); - return vaddr < 0 ? vaddr : 0; -} - -#define EEPROM_MAGIC 0x38E2F10C - -static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, - u8 *data) -{ - int i, err = 0; - struct adapter *adapter = netdev2adap(dev); - - u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - e->magic = EEPROM_MAGIC; - for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) - err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); - - if (!err) - memcpy(data, buf + e->offset, e->len); - kfree(buf); - return err; -} - -static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, - u8 *data) -{ - u8 *buf; - int err = 0; - u32 aligned_offset, aligned_len, *p; - struct adapter *adapter = netdev2adap(dev); - - if (eeprom->magic != EEPROM_MAGIC) - return -EINVAL; - - aligned_offset = eeprom->offset & ~3; - aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; - - if (adapter->fn > 0) { - u32 start = 1024 + adapter->fn * EEPROMPFSIZE; - - if (aligned_offset < start || - aligned_offset + aligned_len > start + EEPROMPFSIZE) - return -EPERM; - } - - if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { - /* - * RMW possibly needed for first or last words. - */ - buf = kmalloc(aligned_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); - if (!err && aligned_len > 4) - err = eeprom_rd_phys(adapter, - aligned_offset + aligned_len - 4, - (u32 *)&buf[aligned_len - 4]); - if (err) - goto out; - memcpy(buf + (eeprom->offset & 3), data, eeprom->len); - } else - buf = data; - - err = t4_seeprom_wp(adapter, false); - if (err) - goto out; - - for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { - err = eeprom_wr_phys(adapter, aligned_offset, *p); - aligned_offset += 4; - } - - if (!err) - err = t4_seeprom_wp(adapter, true); -out: - if (buf != data) - kfree(buf); - return err; -} - -static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) -{ - int ret; - const struct firmware *fw; - struct adapter *adap = netdev2adap(netdev); - unsigned int mbox = PCIE_FW_MASTER_M + 1; - - ef->data[sizeof(ef->data) - 1] = '\0'; - ret = request_firmware(&fw, ef->data, adap->pdev_dev); - if (ret < 0) - return ret; - - /* If the adapter has been fully initialized then we'll go ahead and - * try to get the firmware's cooperation in upgrading to the new - * firmware image otherwise we'll try to do the entire job from the - * host ... and we always "force" the operation in this path. - */ - if (adap->flags & FULL_INIT_DONE) - mbox = adap->mbox; - - ret = t4_fw_upgrade(adap, mbox, fw->data, fw->size, 1); - release_firmware(fw); - if (!ret) - dev_info(adap->pdev_dev, "loaded firmware %s," - " reload cxgb4 driver\n", ef->data); - return ret; -} - -#define WOL_SUPPORTED (WAKE_BCAST | WAKE_MAGIC) -#define BCAST_CRC 0xa0ccc1a6 - -static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - wol->supported = WAKE_BCAST | WAKE_MAGIC; - wol->wolopts = netdev2adap(dev)->wol; - memset(&wol->sopass, 0, sizeof(wol->sopass)); -} - -static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - int err = 0; - struct port_info *pi = netdev_priv(dev); - - if (wol->wolopts & ~WOL_SUPPORTED) - return -EINVAL; - t4_wol_magic_enable(pi->adapter, pi->tx_chan, - (wol->wolopts & WAKE_MAGIC) ? dev->dev_addr : NULL); - if (wol->wolopts & WAKE_BCAST) { - err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0xfe, ~0ULL, - ~0ULL, 0, false); - if (!err) - err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 1, - ~6ULL, ~0ULL, BCAST_CRC, true); - } else - t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0, 0, 0, 0, false); - return err; -} - static int cxgb_set_features(struct net_device *dev, netdev_features_t features) { const struct port_info *pi = netdev_priv(dev); @@ -2867,144 +1409,6 @@ static int cxgb_set_features(struct net_device *dev, netdev_features_t features) return err; } -static u32 get_rss_table_size(struct net_device *dev) -{ - const struct port_info *pi = netdev_priv(dev); - - return pi->rss_size; -} - -static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc) -{ - const struct port_info *pi = netdev_priv(dev); - unsigned int n = pi->rss_size; - - if (hfunc) - *hfunc = ETH_RSS_HASH_TOP; - if (!p) - return 0; - while (n--) - p[n] = pi->rss[n]; - return 0; -} - -static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key, - const u8 hfunc) -{ - unsigned int i; - struct port_info *pi = netdev_priv(dev); - - /* We require at least one supported parameter to be changed and no - * change in any of the unsupported parameters - */ - if (key || - (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) - return -EOPNOTSUPP; - if (!p) - return 0; - - for (i = 0; i < pi->rss_size; i++) - pi->rss[i] = p[i]; - if (pi->adapter->flags & FULL_INIT_DONE) - return write_rss(pi, pi->rss); - return 0; -} - -static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, - u32 *rules) -{ - const struct port_info *pi = netdev_priv(dev); - - switch (info->cmd) { - case ETHTOOL_GRXFH: { - unsigned int v = pi->rss_mode; - - info->data = 0; - switch (info->flow_type) { - case TCP_V4_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case UDP_V4_FLOW: - if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) && - (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case SCTP_V4_FLOW: - case AH_ESP_V4_FLOW: - case IPV4_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case TCP_V6_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case UDP_V6_FLOW: - if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) && - (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case SCTP_V6_FLOW: - case AH_ESP_V6_FLOW: - case IPV6_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - } - return 0; - } - case ETHTOOL_GRXRINGS: - info->data = pi->nqsets; - return 0; - } - return -EOPNOTSUPP; -} - -static const struct ethtool_ops cxgb_ethtool_ops = { - .get_settings = get_settings, - .set_settings = set_settings, - .get_drvinfo = get_drvinfo, - .get_msglevel = get_msglevel, - .set_msglevel = set_msglevel, - .get_ringparam = get_sge_param, - .set_ringparam = set_sge_param, - .get_coalesce = get_coalesce, - .set_coalesce = set_coalesce, - .get_eeprom_len = get_eeprom_len, - .get_eeprom = get_eeprom, - .set_eeprom = set_eeprom, - .get_pauseparam = get_pauseparam, - .set_pauseparam = set_pauseparam, - .get_link = ethtool_op_get_link, - .get_strings = get_strings, - .set_phys_id = identify_port, - .nway_reset = restart_autoneg, - .get_sset_count = get_sset_count, - .get_ethtool_stats = get_stats, - .get_regs_len = get_regs_len, - .get_regs = get_regs, - .get_wol = get_wol, - .set_wol = set_wol, - .get_rxnfc = get_rxnfc, - .get_rxfh_indir_size = get_rss_table_size, - .get_rxfh = get_rss_table, - .set_rxfh = set_rss_table, - .flash_device = set_flash, -}; - static int setup_debugfs(struct adapter *adap) { if (IS_ERR_OR_NULL(adap->debugfs_root)) @@ -5689,7 +4093,7 @@ static inline void init_rspq(struct adapter *adap, struct sge_rspq *q, unsigned int size, unsigned int iqe_size) { q->adap = adap; - set_rspq_intr_params(q, us, cnt); + cxgb4_set_rspq_intr_params(q, us, cnt); q->iqe_len = iqe_size; q->size = size; } @@ -6184,7 +4588,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->dcbnl_ops = &cxgb4_dcb_ops; cxgb4_dcb_state_init(netdev); #endif - netdev->ethtool_ops = &cxgb_ethtool_ops; + cxgb4_set_ethtool_ops(netdev); } pci_set_drvdata(pdev, adapter); diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index c438f3895c40..e622214e2eca 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -1968,7 +1968,7 @@ static int process_responses(struct sge_rspq *q, int budget) if (!is_new_response(rc, q)) break; - rmb(); + dma_rmb(); rsp_type = RSPD_TYPE(rc->type_gen); if (likely(rsp_type == RSP_TYPE_FLBUF)) { struct page_frag *fp; @@ -2160,7 +2160,7 @@ static unsigned int process_intrq(struct adapter *adap) if (!is_new_response(rc, q)) break; - rmb(); + dma_rmb(); if (RSPD_TYPE(rc->type_gen) == RSP_TYPE_INTR) { unsigned int qid = ntohl(rc->pldbuflen_qid); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 5ed8db977432..5959e3ae72da 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -625,6 +625,734 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, return 0; } +/** + * t4_get_regs_len - return the size of the chips register set + * @adapter: the adapter + * + * Returns the size of the chip's BAR0 register space. + */ +unsigned int t4_get_regs_len(struct adapter *adapter) +{ + unsigned int chip_version = CHELSIO_CHIP_VERSION(adapter->params.chip); + + switch (chip_version) { + case CHELSIO_T4: + return T4_REGMAP_SIZE; + + case CHELSIO_T5: + return T5_REGMAP_SIZE; + } + + dev_err(adapter->pdev_dev, + "Unsupported chip version %d\n", chip_version); + return 0; +} + +/** + * t4_get_regs - read chip registers into provided buffer + * @adap: the adapter + * @buf: register buffer + * @buf_size: size (in bytes) of register buffer + * + * If the provided register buffer isn't large enough for the chip's + * full register range, the register dump will be truncated to the + * register buffer's size. + */ +void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) +{ + static const unsigned int t4_reg_ranges[] = { + 0x1008, 0x1108, + 0x1180, 0x11b4, + 0x11fc, 0x123c, + 0x1300, 0x173c, + 0x1800, 0x18fc, + 0x3000, 0x30d8, + 0x30e0, 0x5924, + 0x5960, 0x59d4, + 0x5a00, 0x5af8, + 0x6000, 0x6098, + 0x6100, 0x6150, + 0x6200, 0x6208, + 0x6240, 0x6248, + 0x6280, 0x6338, + 0x6370, 0x638c, + 0x6400, 0x643c, + 0x6500, 0x6524, + 0x6a00, 0x6a38, + 0x6a60, 0x6a78, + 0x6b00, 0x6b84, + 0x6bf0, 0x6c84, + 0x6cf0, 0x6d84, + 0x6df0, 0x6e84, + 0x6ef0, 0x6f84, + 0x6ff0, 0x7084, + 0x70f0, 0x7184, + 0x71f0, 0x7284, + 0x72f0, 0x7384, + 0x73f0, 0x7450, + 0x7500, 0x7530, + 0x7600, 0x761c, + 0x7680, 0x76cc, + 0x7700, 0x7798, + 0x77c0, 0x77fc, + 0x7900, 0x79fc, + 0x7b00, 0x7c38, + 0x7d00, 0x7efc, + 0x8dc0, 0x8e1c, + 0x8e30, 0x8e78, + 0x8ea0, 0x8f6c, + 0x8fc0, 0x9074, + 0x90fc, 0x90fc, + 0x9400, 0x9458, + 0x9600, 0x96bc, + 0x9800, 0x9808, + 0x9820, 0x983c, + 0x9850, 0x9864, + 0x9c00, 0x9c6c, + 0x9c80, 0x9cec, + 0x9d00, 0x9d6c, + 0x9d80, 0x9dec, + 0x9e00, 0x9e6c, + 0x9e80, 0x9eec, + 0x9f00, 0x9f6c, + 0x9f80, 0x9fec, + 0xd004, 0xd03c, + 0xdfc0, 0xdfe0, + 0xe000, 0xea7c, + 0xf000, 0x11110, + 0x11118, 0x11190, + 0x19040, 0x1906c, + 0x19078, 0x19080, + 0x1908c, 0x19124, + 0x19150, 0x191b0, + 0x191d0, 0x191e8, + 0x19238, 0x1924c, + 0x193f8, 0x19474, + 0x19490, 0x194f8, + 0x19800, 0x19f30, + 0x1a000, 0x1a06c, + 0x1a0b0, 0x1a120, + 0x1a128, 0x1a138, + 0x1a190, 0x1a1c4, + 0x1a1fc, 0x1a1fc, + 0x1e040, 0x1e04c, + 0x1e284, 0x1e28c, + 0x1e2c0, 0x1e2c0, + 0x1e2e0, 0x1e2e0, + 0x1e300, 0x1e384, + 0x1e3c0, 0x1e3c8, + 0x1e440, 0x1e44c, + 0x1e684, 0x1e68c, + 0x1e6c0, 0x1e6c0, + 0x1e6e0, 0x1e6e0, + 0x1e700, 0x1e784, + 0x1e7c0, 0x1e7c8, + 0x1e840, 0x1e84c, + 0x1ea84, 0x1ea8c, + 0x1eac0, 0x1eac0, + 0x1eae0, 0x1eae0, + 0x1eb00, 0x1eb84, + 0x1ebc0, 0x1ebc8, + 0x1ec40, 0x1ec4c, + 0x1ee84, 0x1ee8c, + 0x1eec0, 0x1eec0, + 0x1eee0, 0x1eee0, + 0x1ef00, 0x1ef84, + 0x1efc0, 0x1efc8, + 0x1f040, 0x1f04c, + 0x1f284, 0x1f28c, + 0x1f2c0, 0x1f2c0, + 0x1f2e0, 0x1f2e0, + 0x1f300, 0x1f384, + 0x1f3c0, 0x1f3c8, + 0x1f440, 0x1f44c, + 0x1f684, 0x1f68c, + 0x1f6c0, 0x1f6c0, + 0x1f6e0, 0x1f6e0, + 0x1f700, 0x1f784, + 0x1f7c0, 0x1f7c8, + 0x1f840, 0x1f84c, + 0x1fa84, 0x1fa8c, + 0x1fac0, 0x1fac0, + 0x1fae0, 0x1fae0, + 0x1fb00, 0x1fb84, + 0x1fbc0, 0x1fbc8, + 0x1fc40, 0x1fc4c, + 0x1fe84, 0x1fe8c, + 0x1fec0, 0x1fec0, + 0x1fee0, 0x1fee0, + 0x1ff00, 0x1ff84, + 0x1ffc0, 0x1ffc8, + 0x20000, 0x2002c, + 0x20100, 0x2013c, + 0x20190, 0x201c8, + 0x20200, 0x20318, + 0x20400, 0x20528, + 0x20540, 0x20614, + 0x21000, 0x21040, + 0x2104c, 0x21060, + 0x210c0, 0x210ec, + 0x21200, 0x21268, + 0x21270, 0x21284, + 0x212fc, 0x21388, + 0x21400, 0x21404, + 0x21500, 0x21518, + 0x2152c, 0x2153c, + 0x21550, 0x21554, + 0x21600, 0x21600, + 0x21608, 0x21628, + 0x21630, 0x2163c, + 0x21700, 0x2171c, + 0x21780, 0x2178c, + 0x21800, 0x21c38, + 0x21c80, 0x21d7c, + 0x21e00, 0x21e04, + 0x22000, 0x2202c, + 0x22100, 0x2213c, + 0x22190, 0x221c8, + 0x22200, 0x22318, + 0x22400, 0x22528, + 0x22540, 0x22614, + 0x23000, 0x23040, + 0x2304c, 0x23060, + 0x230c0, 0x230ec, + 0x23200, 0x23268, + 0x23270, 0x23284, + 0x232fc, 0x23388, + 0x23400, 0x23404, + 0x23500, 0x23518, + 0x2352c, 0x2353c, + 0x23550, 0x23554, + 0x23600, 0x23600, + 0x23608, 0x23628, + 0x23630, 0x2363c, + 0x23700, 0x2371c, + 0x23780, 0x2378c, + 0x23800, 0x23c38, + 0x23c80, 0x23d7c, + 0x23e00, 0x23e04, + 0x24000, 0x2402c, + 0x24100, 0x2413c, + 0x24190, 0x241c8, + 0x24200, 0x24318, + 0x24400, 0x24528, + 0x24540, 0x24614, + 0x25000, 0x25040, + 0x2504c, 0x25060, + 0x250c0, 0x250ec, + 0x25200, 0x25268, + 0x25270, 0x25284, + 0x252fc, 0x25388, + 0x25400, 0x25404, + 0x25500, 0x25518, + 0x2552c, 0x2553c, + 0x25550, 0x25554, + 0x25600, 0x25600, + 0x25608, 0x25628, + 0x25630, 0x2563c, + 0x25700, 0x2571c, + 0x25780, 0x2578c, + 0x25800, 0x25c38, + 0x25c80, 0x25d7c, + 0x25e00, 0x25e04, + 0x26000, 0x2602c, + 0x26100, 0x2613c, + 0x26190, 0x261c8, + 0x26200, 0x26318, + 0x26400, 0x26528, + 0x26540, 0x26614, + 0x27000, 0x27040, + 0x2704c, 0x27060, + 0x270c0, 0x270ec, + 0x27200, 0x27268, + 0x27270, 0x27284, + 0x272fc, 0x27388, + 0x27400, 0x27404, + 0x27500, 0x27518, + 0x2752c, 0x2753c, + 0x27550, 0x27554, + 0x27600, 0x27600, + 0x27608, 0x27628, + 0x27630, 0x2763c, + 0x27700, 0x2771c, + 0x27780, 0x2778c, + 0x27800, 0x27c38, + 0x27c80, 0x27d7c, + 0x27e00, 0x27e04 + }; + + static const unsigned int t5_reg_ranges[] = { + 0x1008, 0x1148, + 0x1180, 0x11b4, + 0x11fc, 0x123c, + 0x1280, 0x173c, + 0x1800, 0x18fc, + 0x3000, 0x3028, + 0x3060, 0x30d8, + 0x30e0, 0x30fc, + 0x3140, 0x357c, + 0x35a8, 0x35cc, + 0x35ec, 0x35ec, + 0x3600, 0x5624, + 0x56cc, 0x575c, + 0x580c, 0x5814, + 0x5890, 0x58bc, + 0x5940, 0x59dc, + 0x59fc, 0x5a18, + 0x5a60, 0x5a9c, + 0x5b9c, 0x5bfc, + 0x6000, 0x6040, + 0x6058, 0x614c, + 0x7700, 0x7798, + 0x77c0, 0x78fc, + 0x7b00, 0x7c54, + 0x7d00, 0x7efc, + 0x8dc0, 0x8de0, + 0x8df8, 0x8e84, + 0x8ea0, 0x8f84, + 0x8fc0, 0x90f8, + 0x9400, 0x9470, + 0x9600, 0x96f4, + 0x9800, 0x9808, + 0x9820, 0x983c, + 0x9850, 0x9864, + 0x9c00, 0x9c6c, + 0x9c80, 0x9cec, + 0x9d00, 0x9d6c, + 0x9d80, 0x9dec, + 0x9e00, 0x9e6c, + 0x9e80, 0x9eec, + 0x9f00, 0x9f6c, + 0x9f80, 0xa020, + 0xd004, 0xd03c, + 0xdfc0, 0xdfe0, + 0xe000, 0x11088, + 0x1109c, 0x11110, + 0x11118, 0x1117c, + 0x11190, 0x11204, + 0x19040, 0x1906c, + 0x19078, 0x19080, + 0x1908c, 0x19124, + 0x19150, 0x191b0, + 0x191d0, 0x191e8, + 0x19238, 0x19290, + 0x193f8, 0x19474, + 0x19490, 0x194cc, + 0x194f0, 0x194f8, + 0x19c00, 0x19c60, + 0x19c94, 0x19e10, + 0x19e50, 0x19f34, + 0x19f40, 0x19f50, + 0x19f90, 0x19fe4, + 0x1a000, 0x1a06c, + 0x1a0b0, 0x1a120, + 0x1a128, 0x1a138, + 0x1a190, 0x1a1c4, + 0x1a1fc, 0x1a1fc, + 0x1e008, 0x1e00c, + 0x1e040, 0x1e04c, + 0x1e284, 0x1e290, + 0x1e2c0, 0x1e2c0, + 0x1e2e0, 0x1e2e0, + 0x1e300, 0x1e384, + 0x1e3c0, 0x1e3c8, + 0x1e408, 0x1e40c, + 0x1e440, 0x1e44c, + 0x1e684, 0x1e690, + 0x1e6c0, 0x1e6c0, + 0x1e6e0, 0x1e6e0, + 0x1e700, 0x1e784, + 0x1e7c0, 0x1e7c8, + 0x1e808, 0x1e80c, + 0x1e840, 0x1e84c, + 0x1ea84, 0x1ea90, + 0x1eac0, 0x1eac0, + 0x1eae0, 0x1eae0, + 0x1eb00, 0x1eb84, + 0x1ebc0, 0x1ebc8, + 0x1ec08, 0x1ec0c, + 0x1ec40, 0x1ec4c, + 0x1ee84, 0x1ee90, + 0x1eec0, 0x1eec0, + 0x1eee0, 0x1eee0, + 0x1ef00, 0x1ef84, + 0x1efc0, 0x1efc8, + 0x1f008, 0x1f00c, + 0x1f040, 0x1f04c, + 0x1f284, 0x1f290, + 0x1f2c0, 0x1f2c0, + 0x1f2e0, 0x1f2e0, + 0x1f300, 0x1f384, + 0x1f3c0, 0x1f3c8, + 0x1f408, 0x1f40c, + 0x1f440, 0x1f44c, + 0x1f684, 0x1f690, + 0x1f6c0, 0x1f6c0, + 0x1f6e0, 0x1f6e0, + 0x1f700, 0x1f784, + 0x1f7c0, 0x1f7c8, + 0x1f808, 0x1f80c, + 0x1f840, 0x1f84c, + 0x1fa84, 0x1fa90, + 0x1fac0, 0x1fac0, + 0x1fae0, 0x1fae0, + 0x1fb00, 0x1fb84, + 0x1fbc0, 0x1fbc8, + 0x1fc08, 0x1fc0c, + 0x1fc40, 0x1fc4c, + 0x1fe84, 0x1fe90, + 0x1fec0, 0x1fec0, + 0x1fee0, 0x1fee0, + 0x1ff00, 0x1ff84, + 0x1ffc0, 0x1ffc8, + 0x30000, 0x30030, + 0x30100, 0x30144, + 0x30190, 0x301d0, + 0x30200, 0x30318, + 0x30400, 0x3052c, + 0x30540, 0x3061c, + 0x30800, 0x30834, + 0x308c0, 0x30908, + 0x30910, 0x309ac, + 0x30a00, 0x30a04, + 0x30a0c, 0x30a2c, + 0x30a44, 0x30a50, + 0x30a74, 0x30c24, + 0x30d08, 0x30d14, + 0x30d1c, 0x30d20, + 0x30d3c, 0x30d50, + 0x31200, 0x3120c, + 0x31220, 0x31220, + 0x31240, 0x31240, + 0x31600, 0x31600, + 0x31608, 0x3160c, + 0x31a00, 0x31a1c, + 0x31e04, 0x31e20, + 0x31e38, 0x31e3c, + 0x31e80, 0x31e80, + 0x31e88, 0x31ea8, + 0x31eb0, 0x31eb4, + 0x31ec8, 0x31ed4, + 0x31fb8, 0x32004, + 0x32208, 0x3223c, + 0x32600, 0x32630, + 0x32a00, 0x32abc, + 0x32b00, 0x32b70, + 0x33000, 0x33048, + 0x33060, 0x3309c, + 0x330f0, 0x33148, + 0x33160, 0x3319c, + 0x331f0, 0x332e4, + 0x332f8, 0x333e4, + 0x333f8, 0x33448, + 0x33460, 0x3349c, + 0x334f0, 0x33548, + 0x33560, 0x3359c, + 0x335f0, 0x336e4, + 0x336f8, 0x337e4, + 0x337f8, 0x337fc, + 0x33814, 0x33814, + 0x3382c, 0x3382c, + 0x33880, 0x3388c, + 0x338e8, 0x338ec, + 0x33900, 0x33948, + 0x33960, 0x3399c, + 0x339f0, 0x33ae4, + 0x33af8, 0x33b10, + 0x33b28, 0x33b28, + 0x33b3c, 0x33b50, + 0x33bf0, 0x33c10, + 0x33c28, 0x33c28, + 0x33c3c, 0x33c50, + 0x33cf0, 0x33cfc, + 0x34000, 0x34030, + 0x34100, 0x34144, + 0x34190, 0x341d0, + 0x34200, 0x34318, + 0x34400, 0x3452c, + 0x34540, 0x3461c, + 0x34800, 0x34834, + 0x348c0, 0x34908, + 0x34910, 0x349ac, + 0x34a00, 0x34a04, + 0x34a0c, 0x34a2c, + 0x34a44, 0x34a50, + 0x34a74, 0x34c24, + 0x34d08, 0x34d14, + 0x34d1c, 0x34d20, + 0x34d3c, 0x34d50, + 0x35200, 0x3520c, + 0x35220, 0x35220, + 0x35240, 0x35240, + 0x35600, 0x35600, + 0x35608, 0x3560c, + 0x35a00, 0x35a1c, + 0x35e04, 0x35e20, + 0x35e38, 0x35e3c, + 0x35e80, 0x35e80, + 0x35e88, 0x35ea8, + 0x35eb0, 0x35eb4, + 0x35ec8, 0x35ed4, + 0x35fb8, 0x36004, + 0x36208, 0x3623c, + 0x36600, 0x36630, + 0x36a00, 0x36abc, + 0x36b00, 0x36b70, + 0x37000, 0x37048, + 0x37060, 0x3709c, + 0x370f0, 0x37148, + 0x37160, 0x3719c, + 0x371f0, 0x372e4, + 0x372f8, 0x373e4, + 0x373f8, 0x37448, + 0x37460, 0x3749c, + 0x374f0, 0x37548, + 0x37560, 0x3759c, + 0x375f0, 0x376e4, + 0x376f8, 0x377e4, + 0x377f8, 0x377fc, + 0x37814, 0x37814, + 0x3782c, 0x3782c, + 0x37880, 0x3788c, + 0x378e8, 0x378ec, + 0x37900, 0x37948, + 0x37960, 0x3799c, + 0x379f0, 0x37ae4, + 0x37af8, 0x37b10, + 0x37b28, 0x37b28, + 0x37b3c, 0x37b50, + 0x37bf0, 0x37c10, + 0x37c28, 0x37c28, + 0x37c3c, 0x37c50, + 0x37cf0, 0x37cfc, + 0x38000, 0x38030, + 0x38100, 0x38144, + 0x38190, 0x381d0, + 0x38200, 0x38318, + 0x38400, 0x3852c, + 0x38540, 0x3861c, + 0x38800, 0x38834, + 0x388c0, 0x38908, + 0x38910, 0x389ac, + 0x38a00, 0x38a04, + 0x38a0c, 0x38a2c, + 0x38a44, 0x38a50, + 0x38a74, 0x38c24, + 0x38d08, 0x38d14, + 0x38d1c, 0x38d20, + 0x38d3c, 0x38d50, + 0x39200, 0x3920c, + 0x39220, 0x39220, + 0x39240, 0x39240, + 0x39600, 0x39600, + 0x39608, 0x3960c, + 0x39a00, 0x39a1c, + 0x39e04, 0x39e20, + 0x39e38, 0x39e3c, + 0x39e80, 0x39e80, + 0x39e88, 0x39ea8, + 0x39eb0, 0x39eb4, + 0x39ec8, 0x39ed4, + 0x39fb8, 0x3a004, + 0x3a208, 0x3a23c, + 0x3a600, 0x3a630, + 0x3aa00, 0x3aabc, + 0x3ab00, 0x3ab70, + 0x3b000, 0x3b048, + 0x3b060, 0x3b09c, + 0x3b0f0, 0x3b148, + 0x3b160, 0x3b19c, + 0x3b1f0, 0x3b2e4, + 0x3b2f8, 0x3b3e4, + 0x3b3f8, 0x3b448, + 0x3b460, 0x3b49c, + 0x3b4f0, 0x3b548, + 0x3b560, 0x3b59c, + 0x3b5f0, 0x3b6e4, + 0x3b6f8, 0x3b7e4, + 0x3b7f8, 0x3b7fc, + 0x3b814, 0x3b814, + 0x3b82c, 0x3b82c, + 0x3b880, 0x3b88c, + 0x3b8e8, 0x3b8ec, + 0x3b900, 0x3b948, + 0x3b960, 0x3b99c, + 0x3b9f0, 0x3bae4, + 0x3baf8, 0x3bb10, + 0x3bb28, 0x3bb28, + 0x3bb3c, 0x3bb50, + 0x3bbf0, 0x3bc10, + 0x3bc28, 0x3bc28, + 0x3bc3c, 0x3bc50, + 0x3bcf0, 0x3bcfc, + 0x3c000, 0x3c030, + 0x3c100, 0x3c144, + 0x3c190, 0x3c1d0, + 0x3c200, 0x3c318, + 0x3c400, 0x3c52c, + 0x3c540, 0x3c61c, + 0x3c800, 0x3c834, + 0x3c8c0, 0x3c908, + 0x3c910, 0x3c9ac, + 0x3ca00, 0x3ca04, + 0x3ca0c, 0x3ca2c, + 0x3ca44, 0x3ca50, + 0x3ca74, 0x3cc24, + 0x3cd08, 0x3cd14, + 0x3cd1c, 0x3cd20, + 0x3cd3c, 0x3cd50, + 0x3d200, 0x3d20c, + 0x3d220, 0x3d220, + 0x3d240, 0x3d240, + 0x3d600, 0x3d600, + 0x3d608, 0x3d60c, + 0x3da00, 0x3da1c, + 0x3de04, 0x3de20, + 0x3de38, 0x3de3c, + 0x3de80, 0x3de80, + 0x3de88, 0x3dea8, + 0x3deb0, 0x3deb4, + 0x3dec8, 0x3ded4, + 0x3dfb8, 0x3e004, + 0x3e208, 0x3e23c, + 0x3e600, 0x3e630, + 0x3ea00, 0x3eabc, + 0x3eb00, 0x3eb70, + 0x3f000, 0x3f048, + 0x3f060, 0x3f09c, + 0x3f0f0, 0x3f148, + 0x3f160, 0x3f19c, + 0x3f1f0, 0x3f2e4, + 0x3f2f8, 0x3f3e4, + 0x3f3f8, 0x3f448, + 0x3f460, 0x3f49c, + 0x3f4f0, 0x3f548, + 0x3f560, 0x3f59c, + 0x3f5f0, 0x3f6e4, + 0x3f6f8, 0x3f7e4, + 0x3f7f8, 0x3f7fc, + 0x3f814, 0x3f814, + 0x3f82c, 0x3f82c, + 0x3f880, 0x3f88c, + 0x3f8e8, 0x3f8ec, + 0x3f900, 0x3f948, + 0x3f960, 0x3f99c, + 0x3f9f0, 0x3fae4, + 0x3faf8, 0x3fb10, + 0x3fb28, 0x3fb28, + 0x3fb3c, 0x3fb50, + 0x3fbf0, 0x3fc10, + 0x3fc28, 0x3fc28, + 0x3fc3c, 0x3fc50, + 0x3fcf0, 0x3fcfc, + 0x40000, 0x4000c, + 0x40040, 0x40068, + 0x40080, 0x40144, + 0x40180, 0x4018c, + 0x40200, 0x40298, + 0x402ac, 0x4033c, + 0x403f8, 0x403fc, + 0x41304, 0x413c4, + 0x41400, 0x4141c, + 0x41480, 0x414d0, + 0x44000, 0x44078, + 0x440c0, 0x44278, + 0x442c0, 0x44478, + 0x444c0, 0x44678, + 0x446c0, 0x44878, + 0x448c0, 0x449fc, + 0x45000, 0x45068, + 0x45080, 0x45084, + 0x450a0, 0x450b0, + 0x45200, 0x45268, + 0x45280, 0x45284, + 0x452a0, 0x452b0, + 0x460c0, 0x460e4, + 0x47000, 0x4708c, + 0x47200, 0x47250, + 0x47400, 0x47420, + 0x47600, 0x47618, + 0x47800, 0x47814, + 0x48000, 0x4800c, + 0x48040, 0x48068, + 0x48080, 0x48144, + 0x48180, 0x4818c, + 0x48200, 0x48298, + 0x482ac, 0x4833c, + 0x483f8, 0x483fc, + 0x49304, 0x493c4, + 0x49400, 0x4941c, + 0x49480, 0x494d0, + 0x4c000, 0x4c078, + 0x4c0c0, 0x4c278, + 0x4c2c0, 0x4c478, + 0x4c4c0, 0x4c678, + 0x4c6c0, 0x4c878, + 0x4c8c0, 0x4c9fc, + 0x4d000, 0x4d068, + 0x4d080, 0x4d084, + 0x4d0a0, 0x4d0b0, + 0x4d200, 0x4d268, + 0x4d280, 0x4d284, + 0x4d2a0, 0x4d2b0, + 0x4e0c0, 0x4e0e4, + 0x4f000, 0x4f08c, + 0x4f200, 0x4f250, + 0x4f400, 0x4f420, + 0x4f600, 0x4f618, + 0x4f800, 0x4f814, + 0x50000, 0x500cc, + 0x50400, 0x50400, + 0x50800, 0x508cc, + 0x50c00, 0x50c00, + 0x51000, 0x5101c, + 0x51300, 0x51308, + }; + + u32 *buf_end = (u32 *)((char *)buf + buf_size); + const unsigned int *reg_ranges; + int reg_ranges_size, range; + unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); + + /* Select the right set of register ranges to dump depending on the + * adapter chip type. + */ + switch (chip_version) { + case CHELSIO_T4: + reg_ranges = t4_reg_ranges; + reg_ranges_size = ARRAY_SIZE(t4_reg_ranges); + break; + + case CHELSIO_T5: + reg_ranges = t5_reg_ranges; + reg_ranges_size = ARRAY_SIZE(t5_reg_ranges); + break; + + default: + dev_err(adap->pdev_dev, + "Unsupported chip version %d\n", chip_version); + return; + } + + /* Clear the register buffer and insert the appropriate register + * values selected by the above register ranges. + */ + memset(buf, 0, buf_size); + for (range = 0; range < reg_ranges_size; range += 2) { + unsigned int reg = reg_ranges[range]; + unsigned int last_reg = reg_ranges[range + 1]; + u32 *bufp = (u32 *)((char *)buf + reg); + + /* Iterate across the register range filling in the register + * buffer but don't write past the end of the register buffer. + */ + while (reg <= last_reg && bufp < buf_end) { + *bufp++ = t4_read_reg(adap, reg); + reg += sizeof(u32); + } + } +} + #define EEPROM_STAT_ADDR 0x7bfc #define VPD_BASE 0x400 #define VPD_BASE_OLD 0 diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index 7715982230e5..482f6de6817d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -1751,7 +1751,7 @@ static int process_responses(struct sge_rspq *rspq, int budget) * Figure out what kind of response we've received from the * SGE. */ - rmb(); + dma_rmb(); rsp_type = RSPD_TYPE(rc->type_gen); if (likely(rsp_type == RSP_TYPE_FLBUF)) { struct page_frag *fp; @@ -1935,7 +1935,7 @@ static unsigned int process_intrq(struct adapter *adapter) * error and go on to the next response message. This should * never happen ... */ - rmb(); + dma_rmb(); if (unlikely(RSPD_TYPE(rc->type_gen) != RSP_TYPE_INTR)) { dev_err(adapter->pdev_dev, "Unexpected INTRQ response type %d\n", diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index 05f88394f9a5..1a450f4b6b12 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -899,7 +899,7 @@ static int e100_exec_cb(struct nic *nic, struct sk_buff *skb, /* Order is important otherwise we'll be in a race with h/w: * set S-bit in current first, then clear S-bit in previous. */ cb->command |= cpu_to_le16(cb_s); - wmb(); + dma_wmb(); cb->prev->command &= cpu_to_le16(~cb_s); while (nic->cb_to_send != nic->cb_to_use) { @@ -1843,7 +1843,7 @@ static int e100_tx_clean(struct nic *nic) for (cb = nic->cb_to_clean; cb->status & cpu_to_le16(cb_complete); cb = nic->cb_to_clean = cb->next) { - rmb(); /* read skb after status */ + dma_rmb(); /* read skb after status */ netif_printk(nic, tx_done, KERN_DEBUG, nic->netdev, "cb[%d]->status = 0x%04X\n", (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)), @@ -1993,7 +1993,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, netif_printk(nic, rx_status, KERN_DEBUG, nic->netdev, "status=0x%04X\n", rfd_status); - rmb(); /* read size after status bit */ + dma_rmb(); /* read size after status bit */ /* If data isn't ready, nothing to indicate */ if (unlikely(!(rfd_status & cb_complete))) { diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index b548ef0cf56b..983eb4e6f7aa 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -3856,7 +3856,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter, while ((eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && (count < tx_ring->count)) { bool cleaned = false; - rmb(); /* read buffer_info after eop_desc */ + dma_rmb(); /* read buffer_info after eop_desc */ for ( ; !cleaned; count++) { tx_desc = E1000_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; @@ -4154,7 +4154,7 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, if (*work_done >= work_to_do) break; (*work_done)++; - rmb(); /* read descriptor and rx_buffer_info after status DD */ + dma_rmb(); /* read descriptor and rx_buffer_info after status DD */ status = rx_desc->status; @@ -4375,7 +4375,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, if (*work_done >= work_to_do) break; (*work_done)++; - rmb(); /* read descriptor and rx_buffer_info after status DD */ + dma_rmb(); /* read descriptor and rx_buffer_info after status DD */ status = rx_desc->status; length = le16_to_cpu(rx_desc->length); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 4e56c3195989..74ec185a697f 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -947,7 +947,7 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done, if (*work_done >= work_to_do) break; (*work_done)++; - rmb(); /* read descriptor and rx_buffer_info after status DD */ + dma_rmb(); /* read descriptor and rx_buffer_info after status DD */ skb = buffer_info->skb; buffer_info->skb = NULL; @@ -1232,7 +1232,7 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring) (count < tx_ring->count)) { bool cleaned = false; - rmb(); /* read buffer_info after eop_desc */ + dma_rmb(); /* read buffer_info after eop_desc */ for (; !cleaned; count++) { tx_desc = E1000_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; @@ -1332,7 +1332,7 @@ static bool e1000_clean_rx_irq_ps(struct e1000_ring *rx_ring, int *work_done, break; (*work_done)++; skb = buffer_info->skb; - rmb(); /* read descriptor and rx_buffer_info after status DD */ + dma_rmb(); /* read descriptor and rx_buffer_info after status DD */ /* in the packet split case this is header only */ prefetch(skb->data - NET_IP_ALIGN); @@ -1536,7 +1536,7 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done, if (*work_done >= work_to_do) break; (*work_done)++; - rmb(); /* read descriptor and rx_buffer_info after status DD */ + dma_rmb(); /* read descriptor and rx_buffer_info after status DD */ skb = buffer_info->skb; buffer_info->skb = NULL; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index d8989f9d1798..4bd3a80aba82 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1554,7 +1554,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) * any other fields out of the rx_desc until we know the * DD bit is set. */ - rmb(); + dma_rmb(); if (i40e_rx_is_programming_status(qword)) { i40e_clean_programming_status(rx_ring, rx_desc); I40E_RX_INCREMENT(rx_ring, i); @@ -1745,7 +1745,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) * any other fields out of the rx_desc until we know the * DD bit is set. */ - rmb(); + dma_rmb(); if (i40e_rx_is_programming_status(qword)) { i40e_clean_programming_status(rx_ring, rx_desc); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index e2ddb30e96f5..b077e02a0cc7 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1034,7 +1034,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) * any other fields out of the rx_desc until we know the * DD bit is set. */ - rmb(); + dma_rmb(); rx_bi = &rx_ring->rx_bi[i]; skb = rx_bi->skb; if (likely(!skb)) { @@ -1213,7 +1213,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) * any other fields out of the rx_desc until we know the * DD bit is set. */ - rmb(); + dma_rmb(); rx_bi = &rx_ring->rx_bi[i]; skb = rx_bi->skb; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 79b1501e7951..4fdd3c37e47b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -771,7 +771,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud /* * make sure we read the CQE after we read the ownership bit */ - rmb(); + dma_rmb(); /* Drop packet on bad receive or bad checksum */ if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 55f9f5c5344e..1783705273d8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -416,7 +416,7 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, * make sure we read the CQE after we read the * ownership bit */ - rmb(); + dma_rmb(); if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_CQE_OPCODE_ERROR)) { @@ -667,7 +667,7 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, skb_frag_size(&shinfo->frags[0])); } - wmb(); + dma_wmb(); inl->byte_count = cpu_to_be32(1 << 31 | (skb->len - spc)); } } @@ -804,7 +804,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) data->addr = cpu_to_be64(dma); data->lkey = ring->mr_key; - wmb(); + dma_wmb(); data->byte_count = cpu_to_be32(byte_count); --data; } @@ -821,7 +821,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) data->addr = cpu_to_be64(dma); data->lkey = ring->mr_key; - wmb(); + dma_wmb(); data->byte_count = cpu_to_be32(byte_count); } /* tx completion can avoid cache line miss for common cases */ @@ -938,7 +938,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Ensure new descriptor hits memory * before setting ownership of this descriptor to HW */ - wmb(); + dma_wmb(); tx_desc->ctrl.owner_opcode = op_own; wmb(); @@ -958,7 +958,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Ensure new descriptor hits memory * before setting ownership of this descriptor to HW */ - wmb(); + dma_wmb(); tx_desc->ctrl.owner_opcode = op_own; if (send_doorbell) { wmb(); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 6e70ffee8e87..190fd624bdfe 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -188,7 +188,7 @@ static void slave_event(struct mlx4_dev *dev, u8 slave, struct mlx4_eqe *eqe) memcpy(s_eqe, eqe, dev->caps.eqe_size - 1); s_eqe->slave_id = slave; /* ensure all information is written before setting the ownersip bit */ - wmb(); + dma_wmb(); s_eqe->owner = !!(slave_eq->prod & SLAVE_EVENT_EQ_SIZE) ? 0x0 : 0x80; ++slave_eq->prod; @@ -473,7 +473,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) * Make sure we read EQ entry contents after we've * checked the ownership bit. */ - rmb(); + dma_rmb(); switch (eqe->type) { case MLX4_EVENT_TYPE_COMP: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index dbf190d9b9ad..58800e4f3958 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -208,7 +208,7 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) * Make sure we read EQ entry contents after we've * checked the ownership bit. */ - rmb(); + dma_rmb(); mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n", eq->eqn, eqe_type_str(eqe->type)); diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index 092dcae0d4a9..1e0f72b65459 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -2520,7 +2520,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, DBG_PRINT(INFO_DBG, "%s: Could not allocate skb\n", ring->dev->name); if (first_rxdp) { - wmb(); + dma_wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; } swstats->mem_alloc_fail_cnt++; @@ -2634,7 +2634,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, rxdp->Control_2 |= SET_RXD_MARKER; if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) { if (first_rxdp) { - wmb(); + dma_wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; } first_rxdp = rxdp; @@ -2649,7 +2649,7 @@ end: * and other fields are seen by adapter correctly. */ if (first_rxdp) { - wmb(); + dma_wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; } @@ -6950,7 +6950,7 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) } set_rxd_buffer_size(sp, rxdp, size); - wmb(); + dma_wmb(); /* flip the Ownership bit to Hardware */ rxdp->Control_1 |= RXD_OWN_XENA; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index c0a391983372..2ac9552d1fa3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -97,6 +97,7 @@ struct stmmac_priv { int wolopts; int wol_irq; struct clk *stmmac_clk; + struct clk *pclk; struct reset_control *stmmac_rst; int clk_csr; struct timer_list eee_ctrl_timer; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5336594abed1..06103cad7c77 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2849,6 +2849,16 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, } clk_prepare_enable(priv->stmmac_clk); + priv->pclk = devm_clk_get(priv->device, "pclk"); + if (IS_ERR(priv->pclk)) { + if (PTR_ERR(priv->pclk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto error_pclk_get; + } + priv->pclk = NULL; + } + clk_prepare_enable(priv->pclk); + priv->stmmac_rst = devm_reset_control_get(priv->device, STMMAC_RESOURCE_NAME); if (IS_ERR(priv->stmmac_rst)) { @@ -2934,6 +2944,8 @@ error_mdio_register: error_netdev_register: netif_napi_del(&priv->napi); error_hw_init: + clk_disable_unprepare(priv->pclk); +error_pclk_get: clk_disable_unprepare(priv->stmmac_clk); error_clk_get: free_netdev(ndev); @@ -2965,6 +2977,7 @@ int stmmac_dvr_remove(struct net_device *ndev) unregister_netdev(ndev); if (priv->stmmac_rst) reset_control_assert(priv->stmmac_rst); + clk_disable_unprepare(priv->pclk); clk_disable_unprepare(priv->stmmac_clk); free_netdev(ndev); @@ -3011,6 +3024,7 @@ int stmmac_suspend(struct net_device *ndev) stmmac_set_mac(priv->ioaddr, false); pinctrl_pm_select_sleep_state(priv->device); /* Disable clock in case of PWM is off */ + clk_disable(priv->pclk); clk_disable(priv->stmmac_clk); } spin_unlock_irqrestore(&priv->lock, flags); @@ -3051,6 +3065,7 @@ int stmmac_resume(struct net_device *ndev) pinctrl_pm_select_default_state(priv->device); /* enable the clk prevously disabled */ clk_enable(priv->stmmac_clk); + clk_enable(priv->pclk); /* reset the phy so that it's ready */ if (priv->mii) stmmac_mdio_reset(priv->mii); diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index 74e9b148378c..e23a642357e7 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -718,7 +718,7 @@ static __inline__ void gem_post_rxds(struct gem *gp, int limit) cluster_start = curr = (gp->rx_new & ~(4 - 1)); count = 0; kick = -1; - wmb(); + dma_wmb(); while (curr != limit) { curr = NEXT_RX(curr); if (++count == 4) { @@ -1038,7 +1038,7 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb, if (gem_intme(entry)) ctrl |= TXDCTRL_INTME; txd->buffer = cpu_to_le64(mapping); - wmb(); + dma_wmb(); txd->control_word = cpu_to_le64(ctrl); entry = NEXT_TX(entry); } else { @@ -1076,7 +1076,7 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb, txd = &gp->init_block->txd[entry]; txd->buffer = cpu_to_le64(mapping); - wmb(); + dma_wmb(); txd->control_word = cpu_to_le64(this_ctrl | len); if (gem_intme(entry)) @@ -1086,7 +1086,7 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb, } txd = &gp->init_block->txd[first_entry]; txd->buffer = cpu_to_le64(first_mapping); - wmb(); + dma_wmb(); txd->control_word = cpu_to_le64(ctrl | TXDCTRL_SOF | intme | first_len); } @@ -1585,7 +1585,7 @@ static void gem_clean_rings(struct gem *gp) gp->rx_skbs[i] = NULL; } rxd->status_word = 0; - wmb(); + dma_wmb(); rxd->buffer = 0; } @@ -1647,7 +1647,7 @@ static void gem_init_rings(struct gem *gp) RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); rxd->buffer = cpu_to_le64(dma_addr); - wmb(); + dma_wmb(); rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); skb_reserve(skb, RX_OFFSET); } @@ -1656,7 +1656,7 @@ static void gem_init_rings(struct gem *gp) struct gem_txd *txd = &gb->txd[i]; txd->control_word = 0; - wmb(); + dma_wmb(); txd->buffer = 0; } wmb(); diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index 7a8ca2c7b7df..cf4dcff051d5 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -196,14 +196,14 @@ static u32 sbus_hme_read32(void __iomem *reg) static void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) { rxd->rx_addr = (__force hme32)addr; - wmb(); + dma_wmb(); rxd->rx_flags = (__force hme32)flags; } static void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) { txd->tx_addr = (__force hme32)addr; - wmb(); + dma_wmb(); txd->tx_flags = (__force hme32)flags; } @@ -225,14 +225,14 @@ static u32 pci_hme_read32(void __iomem *reg) static void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) { rxd->rx_addr = (__force hme32)cpu_to_le32(addr); - wmb(); + dma_wmb(); rxd->rx_flags = (__force hme32)cpu_to_le32(flags); } static void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) { txd->tx_addr = (__force hme32)cpu_to_le32(addr); - wmb(); + dma_wmb(); txd->tx_flags = (__force hme32)cpu_to_le32(flags); } @@ -268,12 +268,12 @@ static u32 pci_hme_read_desc32(hme32 *p) sbus_readl(__reg) #define hme_write_rxd(__hp, __rxd, __flags, __addr) \ do { (__rxd)->rx_addr = (__force hme32)(u32)(__addr); \ - wmb(); \ + dma_wmb(); \ (__rxd)->rx_flags = (__force hme32)(u32)(__flags); \ } while(0) #define hme_write_txd(__hp, __txd, __flags, __addr) \ do { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \ - wmb(); \ + dma_wmb(); \ (__txd)->tx_flags = (__force hme32)(u32)(__flags); \ } while(0) #define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p)) @@ -293,12 +293,12 @@ do { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \ readl(__reg) #define hme_write_rxd(__hp, __rxd, __flags, __addr) \ do { (__rxd)->rx_addr = (__force hme32)cpu_to_le32(__addr); \ - wmb(); \ + dma_wmb(); \ (__rxd)->rx_flags = (__force hme32)cpu_to_le32(__flags); \ } while(0) #define hme_write_txd(__hp, __txd, __flags, __addr) \ do { (__txd)->tx_addr = (__force hme32)cpu_to_le32(__addr); \ - wmb(); \ + dma_wmb(); \ (__txd)->tx_flags = (__force hme32)cpu_to_le32(__flags); \ } while(0) static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p) diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 401abf7254d3..53fe200e0b79 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -519,7 +519,7 @@ static int vnet_walk_rx_one(struct vnet_port *port, if (desc->hdr.state != VIO_DESC_READY) return 1; - rmb(); + dma_rmb(); viodbg(DATA, "vio_walk_rx_one desc[%02x:%02x:%08x:%08x:%llx:%llx]\n", desc->hdr.state, desc->hdr.ack, @@ -1380,7 +1380,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* This has to be a non-SMP write barrier because we are writing * to memory which is shared with the peer LDOM. */ - wmb(); + dma_wmb(); d->hdr.state = VIO_DESC_READY; @@ -1395,7 +1395,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) * is marked READY, but start_cons was false. * If so, vnet_ack() should send out the missed "start" trigger. * - * Note that the wmb() above makes sure the cookies et al. are + * Note that the dma_wmb() above makes sure the cookies et al. are * not globally visible before the VIO_DESC_READY, and that the * stores are ordered correctly by the compiler. The consumer will * not proceed until the VIO_DESC_READY is visible assuring that diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 309adee6e791..f0b8b3e0ed7c 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -130,7 +130,6 @@ struct hv_netvsc_packet { u32 status; bool part_of_skb; - struct hv_device *device; bool is_data_pkt; bool xmit_more; /* from skb */ u16 vlan_tci; @@ -189,6 +188,7 @@ int netvsc_send(struct hv_device *device, struct hv_netvsc_packet *packet); void netvsc_linkstatus_callback(struct hv_device *device_obj, struct rndis_message *resp); +void netvsc_xmit_completion(void *context); int netvsc_recv_callback(struct hv_device *device_obj, struct hv_netvsc_packet *packet, struct ndis_tcp_ip_checksum_info *csum_info); @@ -959,6 +959,10 @@ struct ndis_tcp_lso_info { #define NDIS_HASH_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ sizeof(u32)) +/* Total size of all PPI data */ +#define NDIS_ALL_PPI_SIZE (NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE + \ + NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE) + /* Format of Information buffer passed in a SetRequest for the OID */ /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ struct rndis_config_parameter_info { @@ -1171,6 +1175,8 @@ struct rndis_message { #define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \ sizeof(union rndis_message_container)) +#define RNDIS_AND_PPI_SIZE (sizeof(struct rndis_message) + NDIS_ALL_PPI_SIZE) + #define NDIS_PACKET_TYPE_DIRECTED 0x00000001 #define NDIS_PACKET_TYPE_MULTICAST 0x00000002 #define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index f69923695b5b..4d4d497d5762 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -878,7 +878,9 @@ int netvsc_send(struct hv_device *device, packet->send_buf_index = section_index; packet->total_data_buflen += msd_len; - kfree(msdp->pkt); + if (msdp->pkt) + netvsc_xmit_completion(msdp->pkt); + if (packet->xmit_more) { msdp->pkt = packet; msdp->count++; @@ -902,7 +904,7 @@ int netvsc_send(struct hv_device *device, if (m_ret != 0) { netvsc_free_send_slot(net_device, msd_send->send_buf_index); - kfree(msd_send); + netvsc_xmit_completion(msd_send); } } @@ -1011,7 +1013,6 @@ static void netvsc_receive(struct netvsc_device *net_device, } count = vmxferpage_packet->range_cnt; - netvsc_packet->device = device; netvsc_packet->channel = channel; /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index f9db6bc513e9..448716787e73 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -229,7 +229,7 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, return q_idx; } -static void netvsc_xmit_completion(void *context) +void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; struct sk_buff *skb = (struct sk_buff *) @@ -370,50 +370,60 @@ not_ip: static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); - struct hv_netvsc_packet *packet; + struct hv_netvsc_packet *packet = NULL; int ret; unsigned int num_data_pgs; struct rndis_message *rndis_msg; struct rndis_packet *rndis_pkt; u32 rndis_msg_size; bool isvlan; + bool linear = false; struct rndis_per_packet_info *ppi; struct ndis_tcp_ip_checksum_info *csum_info; struct ndis_tcp_lso_info *lso_info; int hdr_offset; u32 net_trans_info; u32 hash; - u32 skb_length = skb->len; - u32 head_room = skb_headroom(skb); + u32 skb_length; + u32 head_room; u32 pkt_sz; struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT]; /* We will atmost need two pages to describe the rndis * header. We can only transmit MAX_PAGE_BUFFER_COUNT number - * of pages in a single packet. + * of pages in a single packet. If skb is scattered around + * more pages we try linearizing it. */ + +check_size: + skb_length = skb->len; + head_room = skb_headroom(skb); num_data_pgs = netvsc_get_slots(skb) + 2; - if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) { - netdev_err(net, "Packet too big: %u\n", skb->len); - dev_kfree_skb(skb); - net->stats.tx_dropped++; - return NETDEV_TX_OK; + if (num_data_pgs > MAX_PAGE_BUFFER_COUNT && linear) { + net_alert_ratelimited("packet too big: %u pages (%u bytes)\n", + num_data_pgs, skb->len); + ret = -EFAULT; + goto drop; + } else if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) { + if (skb_linearize(skb)) { + net_alert_ratelimited("failed to linearize skb\n"); + ret = -ENOMEM; + goto drop; + } + linear = true; + goto check_size; } - pkt_sz = sizeof(struct hv_netvsc_packet) + - sizeof(struct rndis_message) + - NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE + - NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE; + pkt_sz = sizeof(struct hv_netvsc_packet) + RNDIS_AND_PPI_SIZE; if (head_room < pkt_sz) { packet = kmalloc(pkt_sz, GFP_ATOMIC); if (!packet) { /* out of memory, drop packet */ netdev_err(net, "unable to alloc hv_netvsc_packet\n"); - dev_kfree_skb(skb); - net->stats.tx_dropped++; - return NETDEV_TX_OK; + ret = -ENOMEM; + goto drop; } packet->part_of_skb = false; } else { @@ -436,11 +446,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + sizeof(struct hv_netvsc_packet)); - memset(packet->rndis_msg, 0, sizeof(struct rndis_message) + - NDIS_VLAN_PPI_SIZE + - NDIS_CSUM_PPI_SIZE + - NDIS_LSO_PPI_SIZE + - NDIS_HASH_PPI_SIZE); + memset(packet->rndis_msg, 0, RNDIS_AND_PPI_SIZE); /* Set the completion routine */ packet->send_completion = netvsc_xmit_completion; @@ -581,7 +587,7 @@ drop: net->stats.tx_bytes += skb_length; net->stats.tx_packets++; } else { - if (!packet->part_of_skb) + if (packet && !packet->part_of_skb) kfree(packet); if (ret != -EAGAIN) { dev_kfree_skb_any(skb); @@ -872,9 +878,7 @@ static int netvsc_probe(struct hv_device *dev, return -ENOMEM; max_needed_headroom = sizeof(struct hv_netvsc_packet) + - sizeof(struct rndis_message) + - NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE + - NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE; + RNDIS_AND_PPI_SIZE; netif_carrier_off(net); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index a1604376aee1..0d92efefd796 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -47,8 +47,6 @@ struct rndis_request { /* Simplify allocation by having a netvsc packet inline */ struct hv_netvsc_packet pkt; - /* Set 2 pages for rndis requests crossing page boundary */ - struct hv_page_buffer buf[2]; struct rndis_message request_msg; /* diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index b5fecb49a0c6..577c9b071ad9 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1672,7 +1672,8 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags, } #if IS_ENABLED(CONFIG_IPV6) -static int vxlan6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, +static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, __be16 src_port, __be16 dst_port, @@ -1748,7 +1749,7 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - udp_tunnel6_xmit_skb(dst, skb, dev, saddr, daddr, prio, + udp_tunnel6_xmit_skb(dst, sk, skb, dev, saddr, daddr, prio, ttl, src_port, dst_port, !!(vxflags & VXLAN_F_UDP_ZERO_CSUM6_TX)); return 0; @@ -1758,7 +1759,7 @@ err: } #endif -int vxlan_xmit_skb(struct rtable *rt, struct sk_buff *skb, +int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, struct vxlan_metadata *md, bool xnet, u32 vxflags) @@ -1827,7 +1828,7 @@ int vxlan_xmit_skb(struct rtable *rt, struct sk_buff *skb, skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - return udp_tunnel_xmit_skb(rt, skb, src, dst, tos, + return udp_tunnel_xmit_skb(rt, sk, skb, src, dst, tos, ttl, df, src_port, dst_port, xnet, !(vxflags & VXLAN_F_UDP_CSUM)); } @@ -1882,6 +1883,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_rdst *rdst, bool did_rsc) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct sock *sk = vxlan->vn_sock->sock->sk; struct rtable *rt = NULL; const struct iphdr *old_iph; struct flowi4 fl4; @@ -1961,7 +1963,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, md.vni = htonl(vni << 8); md.gbp = skb->mark; - err = vxlan_xmit_skb(rt, skb, fl4.saddr, + err = vxlan_xmit_skb(rt, sk, skb, fl4.saddr, dst->sin.sin_addr.s_addr, tos, ttl, df, src_port, dst_port, &md, !net_eq(vxlan->net, dev_net(vxlan->dev)), @@ -1975,7 +1977,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, iptunnel_xmit_stats(err, &dev->stats, dev->tstats); #if IS_ENABLED(CONFIG_IPV6) } else { - struct sock *sk = vxlan->vn_sock->sock->sk; struct dst_entry *ndst; struct flowi6 fl6; u32 flags; @@ -2021,7 +2022,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, md.vni = htonl(vni << 8); md.gbp = skb->mark; - err = vxlan6_xmit_skb(ndst, skb, dev, &fl6.saddr, &fl6.daddr, + err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr, 0, ttl, src_port, dst_port, &md, !net_eq(vxlan->net, dev_net(vxlan->dev)), vxlan->flags); @@ -2255,11 +2256,8 @@ static int vxlan_stop(struct net_device *dev) int ret = 0; if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip) && - !vxlan_group_used(vn, vxlan)) { + !vxlan_group_used(vn, vxlan)) ret = vxlan_igmp_leave(vxlan); - if (ret) - return ret; - } del_timer_sync(&vxlan->age_timer); diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 88d121d43c08..bcfa01add7cc 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -579,6 +579,7 @@ static int cosa_probe(int base, int irq, int dma) /* Register the network interface */ if (!(chan->netdev = alloc_hdlcdev(chan))) { pr_warn("%s: alloc_hdlcdev failed\n", chan->name); + err = -ENOMEM; goto err_hdlcdev; } dev_to_hdlc(chan->netdev)->attach = cosa_net_attach; diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index bea0f313a7a8..317bc79cc8b9 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -850,6 +850,7 @@ static int lmc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev = alloc_hdlcdev(sc); if (!dev) { printk(KERN_ERR "lmc:alloc_netdev for device failed\n"); + err = -ENOMEM; goto err_hdlcdev; } diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 86d46c196966..284706798c71 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -69,9 +69,15 @@ void ath_fill_led_pin(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - if (AR_SREV_9100(ah) || (ah->led_pin >= 0)) + if (AR_SREV_9100(ah)) return; + if (ah->led_pin >= 0) { + if (!((1 << ah->led_pin) & AR_GPIO_OE_OUT_MASK)) + ath9k_hw_request_gpio(ah, ah->led_pin, "ath9k-led"); + return; + } + if (AR_SREV_9287(ah)) ah->led_pin = ATH_LED_PIN_9287; else if (AR_SREV_9485(sc->sc_ah)) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5cdbdb038371..5e15e8e10ed3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -20,6 +20,7 @@ #include <linux/time.h> #include <linux/bitops.h> #include <linux/etherdevice.h> +#include <linux/gpio.h> #include <asm/unaligned.h> #include "hw.h" @@ -2711,11 +2712,23 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) if (AR_SREV_9271(ah)) val = ~val; - REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), - AR_GPIO_BIT(gpio)); + if ((1 << gpio) & AR_GPIO_OE_OUT_MASK) + REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), + AR_GPIO_BIT(gpio)); + else + gpio_set_value(gpio, val & 1); } EXPORT_SYMBOL(ath9k_hw_set_gpio); +void ath9k_hw_request_gpio(struct ath_hw *ah, u32 gpio, const char *label) +{ + if (gpio >= ah->caps.num_gpio_pins) + return; + + gpio_request_one(gpio, GPIOF_DIR_OUT | GPIOF_INIT_LOW, label); +} +EXPORT_SYMBOL(ath9k_hw_request_gpio); + void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) { REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 92fab1a54697..c1d2d0340feb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1024,6 +1024,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, u32 ah_signal_type); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); +void ath9k_hw_request_gpio(struct ath_hw *ah, u32 gpio, const char *label); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); /* General Operation */ diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 1234399a43dd..caba54ddad25 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -958,6 +958,8 @@ #define AR_SREV_9550(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9550)) +#define AR_SREV_9550_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9550)) #define AR_SREV_9580(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \ @@ -1128,6 +1130,8 @@ enum { #define AR_GPIO_OE_OUT (AR_SREV_9340(ah) ? 0x4030 : \ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)) +#define AR_GPIO_OE_OUT_MASK (AR_SREV_9550_OR_LATER(ah) ? \ + 0x0000000F : 0xFFFFFFFF) #define AR_GPIO_OE_OUT_DRV 0x3 #define AR_GPIO_OE_OUT_DRV_NO 0x0 #define AR_GPIO_OE_OUT_DRV_LOW 0x1 diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 67a2f8c88829..ca533b4321bd 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -227,7 +227,7 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, /* Check if there has been a timeout. */ spin_lock(&wmi->wmi_lock); - if (cmd_id != wmi->last_cmd_id) { + if (be16_to_cpu(hdr->seq_no) != wmi->last_seq_id) { spin_unlock(&wmi->wmi_lock); goto free_skb; } @@ -275,11 +275,16 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, enum wmi_cmd_id cmd, u16 len) { struct wmi_cmd_hdr *hdr; + unsigned long flags; hdr = (struct wmi_cmd_hdr *) skb_push(skb, sizeof(struct wmi_cmd_hdr)); hdr->command_id = cpu_to_be16(cmd); hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); + spin_lock_irqsave(&wmi->wmi_lock, flags); + wmi->last_seq_id = wmi->tx_seq_id; + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid); } @@ -295,7 +300,6 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, struct sk_buff *skb; u8 *data; int time_left, ret = 0; - unsigned long flags; if (ah->ah_flags & AH_UNPLUGGED) return 0; @@ -323,10 +327,6 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, wmi->cmd_rsp_buf = rsp_buf; wmi->cmd_rsp_len = rsp_len; - spin_lock_irqsave(&wmi->wmi_lock, flags); - wmi->last_cmd_id = cmd_id; - spin_unlock_irqrestore(&wmi->wmi_lock, flags); - ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len); if (ret) goto out; diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index aa84a335289a..380175d5ecd7 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -151,7 +151,7 @@ struct wmi { enum htc_endpoint_id ctrl_epid; struct mutex op_mutex; struct completion cmd_wait; - enum wmi_cmd_id last_cmd_id; + u16 last_seq_id; struct sk_buff_head wmi_event_queue; struct tasklet_struct wmi_event_tasklet; u16 tx_seq_id; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 1d7982afc0ad..6837064908be 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -553,7 +553,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, size_t buffersize, bool dma_to_device) { if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr))) - return 1; + return true; switch (ring->type) { case B43_DMA_30BIT: @@ -571,13 +571,13 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, } /* The address is OK. */ - return 0; + return false; address_error: /* We can't support this address. Unmap it again. */ unmap_descbuffer(ring, addr, buffersize, dma_to_device); - return 1; + return true; } static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb) @@ -1099,16 +1099,16 @@ static bool b43_dma_translation_in_low_word(struct b43_wldev *dev, enum b43_dmatype type) { if (type != B43_DMA_64BIT) - return 1; + return true; #ifdef CONFIG_B43_SSB if (dev->dev->bus_type == B43_BUS_SSB && dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI && !(pci_is_pcie(dev->dev->sdev->bus->host_pci) && ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)) - return 1; + return true; #endif - return 0; + return false; } int b43_dma_init(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index b2ed1795130b..f9dd892b9f27 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -427,7 +427,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring, bool dma_to_device) { if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr))) - return 1; + return true; switch (ring->type) { case B43legacy_DMA_30BIT: @@ -441,13 +441,13 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring, } /* The address is OK. */ - return 0; + return false; address_error: /* We can't support this address. Unmap it again. */ unmap_descbuffer(ring, addr, buffersize, dma_to_device); - return 1; + return true; } static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index c4559bcbc707..7c1bdbc02569 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -32,7 +32,7 @@ bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) if (dev->dev->id.revision >= 3) { if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; + return true; } else { /* To prevent CPU fault on PPC, do not read a register * unless the interface is started; however, on resume @@ -40,12 +40,12 @@ bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) * that happens, unconditionally return TRUE. */ if (b43legacy_status(dev) < B43legacy_STAT_STARTED) - return 1; + return true; if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; + return true; } - return 0; + return false; } /* The poll callback for the hardware button. */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index 941b1e41f366..1c4e9dd57960 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c @@ -2949,5 +2949,5 @@ bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi) if (ISNPHY(pi)) return wlc_phy_n_txpower_ipa_ison(pi); else - return 0; + return false; } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 5f1366234a0d..93d4cde0eb31 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -4999,7 +4999,7 @@ void wlc_2064_vco_cal(struct brcms_phy *pi) bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi) { if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) - return 0; + return false; else return (LCNPHY_TX_PWR_CTRL_HW == wlc_lcnphy_get_tx_pwr_ctrl((pi))); diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 9c396a42aec8..ce6321b7d241 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -94,8 +94,8 @@ IWL8000_FW_PRE "-" __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_8000 10 -#define DEFAULT_NVM_FILE_FAMILY_8000A "iwl_nvm_8000.bin" -#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000B.bin" +#define DEFAULT_NVM_FILE_FAMILY_8000B "nvmData-8000B" +#define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" /* Max SDIO RX aggregation size of the ADDBA request/response */ #define MAX_RX_AGG_SIZE_8260_SDIO 28 @@ -177,8 +177,8 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .ht_params = &iwl8000_ht_params, .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, - .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A, + .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B, + .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, .disable_dummy_notification = true, .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, @@ -192,8 +192,8 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = { .ht_params = &iwl8000_ht_params, .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, - .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A, + .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B, + .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, .bt_shared_single_ant = true, .disable_dummy_notification = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 4b190d98a1ec..3f33f753ce2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -92,9 +92,9 @@ static inline bool iwl_has_secure_boot(u32 hw_rev, { /* return 1 only for family 8000 B0 */ if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC)) - return 1; + return true; - return 0; + return false; } /* @@ -228,7 +228,7 @@ struct iwl_pwr_tx_backoff { /** * struct iwl_cfg - * @name: Offical name of the device + * @name: Official name of the device * @fw_name_pre: Firmware filename prefix. The api version and extension * (.ucode) will be added to filename before loading from disk. The * filename is constructed as fw_name_pre<api>.ucode. @@ -303,8 +303,8 @@ struct iwl_cfg { bool lp_xtal_workaround; const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; bool no_power_up_nic_in_init; - const char *default_nvm_file; - const char *default_nvm_file_8000A; + const char *default_nvm_file_B_step; + const char *default_nvm_file_C_step; unsigned int max_rx_agg_size; bool disable_dummy_notification; unsigned int max_tx_agg_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index aefdd9b7c105..7267152e7dc7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -145,7 +145,7 @@ static struct iwlwifi_opmode_table { #define IWL_DEFAULT_SCAN_CHANNELS 40 /* - * struct fw_sec: Just for the image parsing proccess. + * struct fw_sec: Just for the image parsing process. * For the fw storage we are using struct fw_desc. */ struct fw_sec { @@ -241,16 +241,10 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) * previous name and uses the new format. */ if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { - char rev_step[2] = { - 'A' + CSR_HW_REV_STEP(drv->trans->hw_rev), 0 - }; - - /* A-step doesn't have an indication */ - if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP) - rev_step[0] = 0; + char rev_step = 'A' + CSR_HW_REV_STEP(drv->trans->hw_rev); snprintf(drv->firmware_name, sizeof(drv->firmware_name), - "%s%s-%s.ucode", name_pre, rev_step, tag); + "%s%c-%s.ucode", name_pre, rev_step, tag); } IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", @@ -1108,6 +1102,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) const unsigned int api_max = drv->cfg->ucode_api_max; unsigned int api_ok = drv->cfg->ucode_api_ok; const unsigned int api_min = drv->cfg->ucode_api_min; + size_t trigger_tlv_sz[FW_DBG_TRIGGER_MAX]; u32 api_ver; int i; bool load_module = false; @@ -1227,8 +1222,37 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) } } + memset(&trigger_tlv_sz, 0xff, sizeof(trigger_tlv_sz)); + + trigger_tlv_sz[FW_DBG_TRIGGER_MISSED_BEACONS] = + sizeof(struct iwl_fw_dbg_trigger_missed_bcon); + trigger_tlv_sz[FW_DBG_TRIGGER_CHANNEL_SWITCH] = 0; + trigger_tlv_sz[FW_DBG_TRIGGER_FW_NOTIF] = + sizeof(struct iwl_fw_dbg_trigger_cmd); + trigger_tlv_sz[FW_DBG_TRIGGER_MLME] = + sizeof(struct iwl_fw_dbg_trigger_mlme); + trigger_tlv_sz[FW_DBG_TRIGGER_STATS] = + sizeof(struct iwl_fw_dbg_trigger_stats); + trigger_tlv_sz[FW_DBG_TRIGGER_RSSI] = + sizeof(struct iwl_fw_dbg_trigger_low_rssi); + trigger_tlv_sz[FW_DBG_TRIGGER_TXQ_TIMERS] = + sizeof(struct iwl_fw_dbg_trigger_txq_timer); + trigger_tlv_sz[FW_DBG_TRIGGER_TIME_EVENT] = + sizeof(struct iwl_fw_dbg_trigger_time_event); + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) { if (pieces->dbg_trigger_tlv[i]) { + /* + * If the trigger isn't long enough, WARN and exit. + * Someone is trying to debug something and he won't + * be able to catch the bug he is trying to chase. + * We'd better be noisy to be sure he knows what's + * going on. + */ + if (WARN_ON(pieces->dbg_trigger_tlv_len[i] < + (trigger_tlv_sz[i] + + sizeof(struct iwl_fw_dbg_trigger_tlv)))) + goto out_free_fw; drv->fw.dbg_trigger_tlv_len[i] = pieces->dbg_trigger_tlv_len[i]; drv->fw.dbg_trigger_tlv[i] = diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index 67a3a241b331..cda746b33db1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -123,7 +123,7 @@ struct iwl_cfg; * starts the driver: fetches the firmware. This should be called by bus * specific system flows implementations. For example, the bus specific probe * function should do bus related operations only, and then call to this - * function. It returns the driver object or %NULL if an error occured. + * function. It returns the driver object or %NULL if an error occurred. */ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, const struct iwl_cfg *cfg); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c index 25d0105741db..219ca8acca62 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c @@ -248,7 +248,7 @@ static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, otpgp = iwl_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { /* stop in this case */ - /* set the uncorrectable OTP ECC bit for acknowledgement */ + /* set the uncorrectable OTP ECC bit for acknowledgment */ iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n"); @@ -256,7 +256,7 @@ static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, } if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { /* continue in this case */ - /* set the correctable OTP ECC bit for acknowledgement */ + /* set the correctable OTP ECC bit for acknowledgment */ iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); IWL_ERR(trans, "Correctable OTP ECC error, continue read\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 1f7f15eb86da..d45dc021cda2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -445,7 +445,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define RX_LOW_WATERMARK 8 /** - * struct iwl_rb_status - reseve buffer status + * struct iwl_rb_status - reserve buffer status * host memory mapped FH registers * @closed_rb_num [0:11] - Indicates the index of the RB which was closed * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 37b38a585dd1..251bf8dc4a12 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -183,7 +183,7 @@ struct iwl_fw_error_dump_info { * struct iwl_fw_error_dump_fw_mon - FW monitor data * @fw_mon_wr_ptr: the position of the write pointer in the cyclic buffer * @fw_mon_base_ptr: base pointer of the data - * @fw_mon_cycle_cnt: number of wrap arounds + * @fw_mon_cycle_cnt: number of wraparounds * @reserved: for future use * @data: captured data */ @@ -246,10 +246,14 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) * @FW_DBG_TRIGGER_CHANNEL_SWITCH: trigger log collection upon channel switch. * @FW_DBG_TRIGGER_FW_NOTIF: trigger log collection when the firmware sends a * command response or a notification. - * @FW_DB_TRIGGER_RESERVED: reserved + * @FW_DBG_TRIGGER_MLME: trigger log collection upon MLME event. * @FW_DBG_TRIGGER_STATS: trigger log collection upon statistics threshold. * @FW_DBG_TRIGGER_RSSI: trigger log collection when the rssi of the beacon * goes below a threshold. + * @FW_DBG_TRIGGER_TXQ_TIMERS: configures the timers for the Tx queue hang + * detection. + * @FW_DBG_TRIGGER_TIME_EVENT: trigger log collection upon time events related + * events. */ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_INVALID = 0, @@ -258,9 +262,11 @@ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_MISSED_BEACONS, FW_DBG_TRIGGER_CHANNEL_SWITCH, FW_DBG_TRIGGER_FW_NOTIF, - FW_DB_TRIGGER_RESERVED, + FW_DBG_TRIGGER_MLME, FW_DBG_TRIGGER_STATS, FW_DBG_TRIGGER_RSSI, + FW_DBG_TRIGGER_TXQ_TIMERS, + FW_DBG_TRIGGER_TIME_EVENT, /* must be last */ FW_DBG_TRIGGER_MAX, diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 291a3382aa3f..bfdf3faa6c47 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -191,7 +191,7 @@ struct iwl_ucode_capa { * enum iwl_ucode_tlv_flag - ucode API flags * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * was a separate TLV but moved here to save space. - * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, + * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behavior on hidden SSID, * treats good CRC threshold as a boolean * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. @@ -290,6 +290,10 @@ enum iwl_ucode_tlv_api { * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running + * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different + * sources for the MCC. This TLV bit is a future replacement to + * IWL_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR + * is supported. * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC */ enum iwl_ucode_tlv_capa { @@ -307,6 +311,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22), IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = BIT(28), + IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = BIT(29), IWL_UCODE_TLV_CAPA_BT_COEX_RRC = BIT(30), }; @@ -574,6 +579,84 @@ struct iwl_fw_dbg_trigger_low_rssi { } __packed; /** + * struct iwl_fw_dbg_trigger_mlme - configures trigger for mlme events + * @stop_auth_denied: number of denied authentication to collect + * @stop_auth_timeout: number of authentication timeout to collect + * @stop_rx_deauth: number of Rx deauth before to collect + * @stop_tx_deauth: number of Tx deauth before to collect + * @stop_assoc_denied: number of denied association to collect + * @stop_assoc_timeout: number of association timeout to collect + * @stop_connection_loss: number of connection loss to collect + * @start_auth_denied: number of denied authentication to start recording + * @start_auth_timeout: number of authentication timeout to start recording + * @start_rx_deauth: number of Rx deauth to start recording + * @start_tx_deauth: number of Tx deauth to start recording + * @start_assoc_denied: number of denied association to start recording + * @start_assoc_timeout: number of association timeout to start recording + * @start_connection_loss: number of connection loss to start recording + */ +struct iwl_fw_dbg_trigger_mlme { + u8 stop_auth_denied; + u8 stop_auth_timeout; + u8 stop_rx_deauth; + u8 stop_tx_deauth; + + u8 stop_assoc_denied; + u8 stop_assoc_timeout; + u8 stop_connection_loss; + u8 reserved; + + u8 start_auth_denied; + u8 start_auth_timeout; + u8 start_rx_deauth; + u8 start_tx_deauth; + + u8 start_assoc_denied; + u8 start_assoc_timeout; + u8 start_connection_loss; + u8 reserved2; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_txq_timer - configures the Tx queue's timer + * @command_queue: timeout for the command queue in ms + * @bss: timeout for the queues of a BSS (except for TDLS queues) in ms + * @softap: timeout for the queues of a softAP in ms + * @p2p_go: timeout for the queues of a P2P GO in ms + * @p2p_client: timeout for the queues of a P2P client in ms + * @p2p_device: timeout for the queues of a P2P device in ms + * @ibss: timeout for the queues of an IBSS in ms + * @tdls: timeout for the queues of a TDLS station in ms + */ +struct iwl_fw_dbg_trigger_txq_timer { + __le32 command_queue; + __le32 bss; + __le32 softap; + __le32 p2p_go; + __le32 p2p_client; + __le32 p2p_device; + __le32 ibss; + __le32 tdls; + __le32 reserved[4]; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_time_event - configures a time event trigger + * time_Events: a list of tuples <id, action_bitmap>. The driver will issue a + * trigger each time a time event notification that relates to time event + * id with one of the actions in the bitmap is received and + * BIT(notif->status) is set in status_bitmap. + * + */ +struct iwl_fw_dbg_trigger_time_event { + struct { + __le32 id; + __le32 action_bitmap; + __le32 status_bitmap; + } __packed time_events[16]; +} __packed; + +/** * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration. * @id: conf id * @usniffer: should the uSniffer image be used diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 78cac43e2bcd..27c66e477833 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -186,21 +186,14 @@ IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); void iwl_force_nmi(struct iwl_trans *trans) { - /* - * In HW previous to the 8000 HW family, and in the 8000 HW family - * itself when the revision step==0, the DEVICE_SET_NMI_REG is used - * to force an NMI. Otherwise, a different register - - * DEVICE_SET_NMI_8000B_REG - is used. - */ - if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || - (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) { + if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_DRV); iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_HW); } else { - iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, - DEVICE_SET_NMI_8000B_VAL); + iwl_write_prph(trans, DEVICE_SET_NMI_8000_REG, + DEVICE_SET_NMI_8000_VAL); iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_DRV); } diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 774637746427..83903a5025c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -99,14 +99,9 @@ enum family_8000_nvm_offsets { /* NVM SW-Section offset (in words) definitions */ NVM_SW_SECTION_FAMILY_8000 = 0x1C0, NVM_VERSION_FAMILY_8000 = 0, - RADIO_CFG_FAMILY_8000 = 2, - SKU_FAMILY_8000 = 4, - N_HW_ADDRS_FAMILY_8000 = 5, - - /* NVM PHY-SKU-Section offset (in words) for B0 */ - RADIO_CFG_FAMILY_8000_B0 = 0, - SKU_FAMILY_8000_B0 = 2, - N_HW_ADDRS_FAMILY_8000_B0 = 3, + RADIO_CFG_FAMILY_8000 = 0, + SKU_FAMILY_8000 = 2, + N_HW_ADDRS_FAMILY_8000 = 3, /* NVM REGULATORY -Section offset (in words) definitions */ NVM_CHANNELS_FAMILY_8000 = 0, @@ -446,22 +441,16 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, n_used, n_channels); } -static int iwl_get_sku(const struct iwl_cfg *cfg, - const __le16 *nvm_sw, const __le16 *phy_sku, - bool is_family_8000_a_step) +static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw, + const __le16 *phy_sku) { if (cfg->device_family != IWL_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + SKU); - if (!is_family_8000_a_step) - return le32_to_cpup((__le32 *)(phy_sku + - SKU_FAMILY_8000_B0)); - else - return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000)); + return le32_to_cpup((__le32 *)(phy_sku + SKU_FAMILY_8000)); } -static int iwl_get_nvm_version(const struct iwl_cfg *cfg, - const __le16 *nvm_sw) +static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw) { if (cfg->device_family != IWL_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + NVM_VERSION); @@ -470,35 +459,24 @@ static int iwl_get_nvm_version(const struct iwl_cfg *cfg, NVM_VERSION_FAMILY_8000)); } -static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, - const __le16 *nvm_sw, const __le16 *phy_sku, - bool is_family_8000_a_step) +static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw, + const __le16 *phy_sku) { if (cfg->device_family != IWL_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + RADIO_CFG); - if (!is_family_8000_a_step) - return le32_to_cpup((__le32 *)(phy_sku + - RADIO_CFG_FAMILY_8000_B0)); - else - return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000)); + return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000)); } -static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, - const __le16 *nvm_sw, bool is_family_8000_a_step) +static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw) { int n_hw_addr; if (cfg->device_family != IWL_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + N_HW_ADDRS); - if (!is_family_8000_a_step) - n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + - N_HW_ADDRS_FAMILY_8000_B0)); - else - n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + - N_HW_ADDRS_FAMILY_8000)); + n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)); return n_hw_addr & N_HW_ADDR_MASK; } @@ -594,8 +572,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, - u8 tx_chains, u8 rx_chains, - bool lar_fw_supported, bool is_family_8000_a_step, + u8 tx_chains, u8 rx_chains, bool lar_fw_supported, u32 mac_addr0, u32 mac_addr1) { struct iwl_nvm_data *data; @@ -618,15 +595,14 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw); - radio_cfg = - iwl_get_radio_cfg(cfg, nvm_sw, phy_sku, is_family_8000_a_step); + radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw, phy_sku); iwl_set_radio_cfg(cfg, data, radio_cfg); if (data->valid_tx_ant) tx_chains &= data->valid_tx_ant; if (data->valid_rx_ant) rx_chains &= data->valid_rx_ant; - sku = iwl_get_sku(cfg, nvm_sw, phy_sku, is_family_8000_a_step); + sku = iwl_get_sku(cfg, nvm_sw, phy_sku); data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; @@ -635,8 +611,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, data->sku_cap_11ac_enable = data->sku_cap_11n_enable && (sku & NVM_SKU_CAP_11AC_ENABLE); - data->n_hw_addrs = - iwl_get_n_hw_addrs(cfg, nvm_sw, is_family_8000_a_step); + data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { /* Checking for required sections */ diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index c995d2cee3f6..822ba52e0e5a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -78,8 +78,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, - u8 tx_chains, u8 rx_chains, - bool lar_fw_supported, bool is_family_8000_a_step, + u8 tx_chains, u8 rx_chains, bool lar_fw_supported, u32 mac_addr0, u32 mac_addr1); /** diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index 17de6d46222a..ce1cdd7604e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -94,7 +94,7 @@ struct iwl_cfg; * The operational mode has a very simple life cycle. * * 1) The driver layer (iwl-drv.c) chooses the op_mode based on the - * capabilities advertized by the fw file (in TLV format). + * capabilities advertised by the fw file (in TLV format). * 2) The driver layer starts the op_mode (ops->start) * 3) The op_mode registers mac80211 * 4) The op_mode is governed by mac80211 @@ -116,7 +116,7 @@ struct iwl_cfg; * May sleep * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the * HCMD this Rx responds to. Can't sleep. - * @napi_add: NAPI initialisation. The transport is fully responsible for NAPI, + * @napi_add: NAPI initialization. The transport is fully responsible for NAPI, * but the higher layers need to know about it (in particular mac80211 to * to able to call the right NAPI RX functions); this function is needed * to eventually call netif_napi_add() with higher layer involvement. diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c index e893c6eb260c..a105455b6a24 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c @@ -125,7 +125,7 @@ struct iwl_phy_db_chg_txp { } __packed; /* - * phy db - Receieve phy db chunk after calibrations + * phy db - Receive phy db chunk after calibrations */ struct iwl_calib_res_notif_phy_db { __le16 type; diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index bc962888c583..88a57e6e232f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -110,8 +110,8 @@ #define DEVICE_SET_NMI_REG 0x00a01c30 #define DEVICE_SET_NMI_VAL_HW BIT(0) #define DEVICE_SET_NMI_VAL_DRV BIT(7) -#define DEVICE_SET_NMI_8000B_REG 0x00a01c24 -#define DEVICE_SET_NMI_8000B_VAL 0x1000000 +#define DEVICE_SET_NMI_8000_REG 0x00a01c24 +#define DEVICE_SET_NMI_8000_VAL 0x1000000 /* Shared registers (0x0..0x3ff, via target indirect or periphery */ #define SHR_BASE 0x00a10000 @@ -295,25 +295,6 @@ #define OSC_CLK (0xa04068) #define OSC_CLK_FORCE_CONTROL (0x8) -/* SECURE boot registers */ -#define LMPM_SECURE_BOOT_CONFIG_ADDR (0x100) -enum secure_boot_config_reg { - LMPM_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001, - LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, -}; - -#define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0 (0xA01E30) -#define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30) -#define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34) -enum secure_boot_status_reg { - LMPM_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000001, - LMPM_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002, - LMPM_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004, - LMPM_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008, - LMPM_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010, - LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003, -}; - #define FH_UCODE_LOAD_STATUS (0x1AF0) #define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70) enum secure_load_status_reg { @@ -334,8 +315,6 @@ enum secure_load_status_reg { #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) -#define LMPM_SECURE_TIME_OUT (100) /* 10 micro */ - /* Rx FIFO */ #define RXF_SIZE_ADDR (0xa00c88) #define RXF_RD_D_SPACE (0xa00c40) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 11ac5c58527f..6dfed1259260 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -77,10 +77,10 @@ /** * DOC: Transport layer - what is it ? * - * The tranport layer is the layer that deals with the HW directly. It provides + * The transport layer is the layer that deals with the HW directly. It provides * an abstraction of the underlying HW to the upper layer. The transport layer * doesn't provide any policy, algorithm or anything of this kind, but only - * mechanisms to make the HW do something.It is not completely stateless but + * mechanisms to make the HW do something. It is not completely stateless but * close to it. * We will have an implementation for each different supported bus. */ @@ -111,10 +111,10 @@ /** * DOC: Host command section * - * A host command is a commaned issued by the upper layer to the fw. There are + * A host command is a command issued by the upper layer to the fw. There are * several versions of fw that have several APIs. The transport layer is * completely agnostic to these differences. - * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode), + * The transport does provide helper functionality (i.e. SYNC / ASYNC mode), */ #define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) #define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) @@ -195,7 +195,7 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt) * @CMD_WANT_SKB: Not valid with CMD_ASYNC. The caller needs the buffer of * the response. The caller needs to call iwl_free_resp when done. * @CMD_HIGH_PRIO: The command is high priority - it goes to the front of the - * command queue, but after other high priority commands. valid only + * command queue, but after other high priority commands. Valid only * with CMD_ASYNC. * @CMD_SEND_IN_IDLE: The command should be sent even when the trans is idle. * @CMD_MAKE_TRANS_IDLE: The command response should mark the trans as idle. @@ -582,7 +582,7 @@ enum iwl_d0i3_mode { * @cfg - pointer to the configuration * @status: a bit-mask of transport status flags * @dev - pointer to struct device * that represents the device - * @hw_id: a u32 with the ID of the device / subdevice. + * @hw_id: a u32 with the ID of the device / sub-device. * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. * @pm_support: set to true in start_hw if link pm is supported diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 5f8afa5f11a3..a6c48c7b1e16 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1131,6 +1131,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, iwl_trans_d3_suspend(mvm->trans, test); out: if (ret < 0) { + iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); ieee80211_restart_hw(mvm->hw); iwl_mvm_free_nd(mvm); } @@ -1725,6 +1726,10 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, results->matched_profiles = le32_to_cpu(query->matched_profiles); memcpy(results->matches, query->matches, sizeof(results->matches)); +#ifdef CPTCFG_IWLWIFI_DEBUGFS + mvm->last_netdetect_scans = le32_to_cpu(query->n_scans_done); +#endif + out_free_resp: iwl_free_resp(&cmd); return ret; @@ -2016,6 +2021,7 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) __iwl_mvm_resume(mvm, true); rtnl_unlock(); iwl_abort_notification_waits(&mvm->notif_wait); + iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); ieee80211_restart_hw(mvm->hw); /* wait for restart and disconnect all interfaces */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 8c5229892e57..9ac04c1ea706 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1473,26 +1473,6 @@ out: return count; } -static ssize_t iwl_dbgfs_enable_scan_iteration_notif_write(struct iwl_mvm *mvm, - char *buf, - size_t count, - loff_t *ppos) -{ - int val; - - mutex_lock(&mvm->mutex); - - if (kstrtoint(buf, 10, &val)) { - mutex_unlock(&mvm->mutex); - return -EINVAL; - } - - mvm->scan_iter_notif_enabled = val; - mutex_unlock(&mvm->mutex); - - return count; -} - MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); /* Device wide debugfs entries */ @@ -1515,7 +1495,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8); -MVM_DEBUGFS_WRITE_FILE_OPS(enable_scan_iteration_notif, 8); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); @@ -1559,8 +1538,11 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(enable_scan_iteration_notif, mvm->debugfs_dir, - S_IWUSR); + if (!debugfs_create_bool("enable_scan_iteration_notif", + S_IRUSR | S_IWUSR, + mvm->debugfs_dir, + &mvm->scan_iter_notif_enabled)) + goto err; #ifdef CONFIG_IWLWIFI_BCAST_FILTERING if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { @@ -1587,6 +1569,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR, mvm->debugfs_dir, &mvm->d3_wake_sysassert)) goto err; + if (!debugfs_create_u32("last_netdetect_scans", S_IRUSR, + mvm->debugfs_dir, &mvm->last_netdetect_scans)) + goto err; MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR); #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 6d3bea5c59d1..d7658d16e965 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -132,7 +132,7 @@ struct iwl_proto_offload_cmd_common { * @solicited_node_ipv6_addr: broken -- solicited node address exists * for each target address * @target_ipv6_addr: our target addresses - * @ndp_mac_addr: neighbor soliciation response MAC address + * @ndp_mac_addr: neighbor solicitation response MAC address */ struct iwl_proto_offload_cmd_v1 { struct iwl_proto_offload_cmd_common common; @@ -150,7 +150,7 @@ struct iwl_proto_offload_cmd_v1 { * @solicited_node_ipv6_addr: broken -- solicited node address exists * for each target address * @target_ipv6_addr: our target addresses - * @ndp_mac_addr: neighbor soliciation response MAC address + * @ndp_mac_addr: neighbor solicitation response MAC address */ struct iwl_proto_offload_cmd_v2 { struct iwl_proto_offload_cmd_common common; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h index aabaedd3b3ee..f3f3ee0a766b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h @@ -255,7 +255,7 @@ struct iwl_mac_data_p2p_dev { /** * enum iwl_mac_filter_flags - MAC context filter flags * @MAC_FILTER_IN_PROMISC: accept all data frames - * @MAC_FILTER_IN_CONTROL_AND_MGMT: pass all mangement and + * @MAC_FILTER_IN_CONTROL_AND_MGMT: pass all management and * control frames to the host * @MAC_FILTER_ACCEPT_GRP: accept multicast frames * @MAC_FILTER_DIS_DECRYPT: don't decrypt unicast frames diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index a5fbbd637070..4f81dcf57a73 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -103,7 +103,7 @@ struct iwl_ssid_ie { * @SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax * @SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful * (not an error!) - * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repeatition the driver + * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repetition the driver * asked for * @SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events */ @@ -187,11 +187,11 @@ enum scan_framework_client { * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 * @scan_flags: see enum iwl_scan_flags * @channel_count: channels in channel list - * @quiet_time: dwell time, in milisiconds, on quiet channel + * @quiet_time: dwell time, in milliseconds, on quiet channel * @quiet_plcp_th: quiet channel num of packets threshold * @good_CRC_th: passive to active promotion threshold * @rx_chain: RXON rx chain. - * @max_out_time: max TUs to be out of assoceated channel + * @max_out_time: max TUs to be out of associated channel * @suspend_time: pause scan this TUs when returning to service channel * @flags: RXON flags * @filter_flags: RXONfilter @@ -232,7 +232,7 @@ enum iwl_scan_offload_channel_flags { * see enum iwl_scan_offload_channel_flags. * __le16 channel_number: channel number 1-13 etc. * __le16 iter_count: repetition count for the channel. - * __le32 iter_interval: interval between two innteration on one channel. + * __le32 iter_interval: interval between two iterations on one channel. * u8 active_dwell. * u8 passive_dwell. */ @@ -275,8 +275,8 @@ enum iwl_scan_offload_band_selection { /** * iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S * @ssid_index: index to ssid list in fixed part - * @unicast_cipher: encryption olgorithm to match - bitmap - * @aut_alg: authentication olgorithm to match - bitmap + * @unicast_cipher: encryption algorithm to match - bitmap + * @aut_alg: authentication algorithm to match - bitmap * @network_type: enum iwl_scan_offload_network_type * @band_selection: enum iwl_scan_offload_band_selection * @client_bitmap: clients waiting for match - enum scan_framework_client @@ -748,7 +748,7 @@ enum iwl_umac_scan_general_flags { * @flags: bitmap - 0-19: directed scan to i'th ssid. * @channel_num: channel number 1-13 etc. * @iter_count: repetition count for the channel. - * @iter_interval: interval between two scan interations on one channel. + * @iter_interval: interval between two scan iterations on one channel. */ struct iwl_scan_channel_cfg_umac { __le32 flags; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 6cf7d9837ca5..bc5eac4960e1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -526,16 +526,33 @@ int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trigger, - const char *str, size_t len) + const char *fmt, ...) { unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); u16 occurrences = le16_to_cpu(trigger->occurrences); - int ret; + int ret, len = 0; + char buf[64]; if (!occurrences) return 0; - ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), str, + if (fmt) { + va_list ap; + + buf[sizeof(buf) - 1] = '\0'; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + /* check for truncation */ + if (WARN_ON_ONCE(buf[sizeof(buf) - 1])) + buf[sizeof(buf) - 1] = '\0'; + + len = strlen(buf) + 1; + } + + ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, len, delay); if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 581b3b8f29f9..8088c7137f7c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -470,9 +470,8 @@ exit_fail: int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? - mvm->cfg->base_params->wd_timeout : - IWL_WATCHDOG_DISABLED; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, vif, false, false); u32 ac; int ret; @@ -1413,7 +1412,7 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, if (rx_missed_bcon_since_rx >= stop_trig_missed_bcon_since_rx || rx_missed_bcon >= stop_trig_missed_bcon) - iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL, 0); + iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL); } int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 302c8cc50f25..84555170b6f7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -379,11 +379,13 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) { enum iwl_mcc_source used_src; struct ieee80211_regdomain *regd; + int ret; + bool changed; const struct ieee80211_regdomain *r = rtnl_dereference(mvm->hw->wiphy->regd); if (!r) - return 0; + return -ENOENT; /* save the last source in case we overwrite it below */ used_src = mvm->mcc_src; @@ -395,14 +397,19 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) } /* Now set our last stored MCC and source */ - regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src, NULL); + regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src, + &changed); if (IS_ERR_OR_NULL(regd)) return -EIO; - regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); - kfree(regd); + /* update cfg80211 if the regdomain was changed */ + if (changed) + ret = regulatory_set_wiphy_regd_sync_rtnl(mvm->hw->wiphy, regd); + else + ret = 0; - return 0; + kfree(regd); + return ret; } int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) @@ -1007,6 +1014,9 @@ void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm) mvm->fw_dump_desc = NULL; } +#define IWL8260_ICCM_OFFSET 0x44000 /* Only for B-step */ +#define IWL8260_ICCM_LEN 0xC000 /* Only for B-step */ + void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { struct iwl_fw_error_dump_file *dump_file; @@ -1022,16 +1032,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - /* W/A for 8000 HW family A-step */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) { - if (smem_len) - smem_len = 0x38000; - - if (sram2_len) - sram2_len = 0x10000; - } - fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); if (!fw_error_dump) return; @@ -1083,6 +1083,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) fifo_data_len + sizeof(*dump_info); + /* + * In 8000 HW family B-step include the ICCM (which resides separately) + */ + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + + IWL8260_ICCM_LEN; + if (mvm->fw_dump_desc) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + mvm->fw_dump_desc->len; @@ -1170,6 +1178,19 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_mem->data, sram2_len); } + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) { + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + dump_data->len = cpu_to_le32(IWL8260_ICCM_LEN + + sizeof(*dump_mem)); + dump_mem = (void *)dump_data->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); + dump_mem->offset = cpu_to_le32(IWL8260_ICCM_OFFSET); + iwl_trans_read_mem_bytes(mvm->trans, IWL8260_ICCM_OFFSET, + dump_mem->data, IWL8260_ICCM_LEN); + } + fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); fw_error_dump->op_mode_len = file_len; if (fw_error_dump->trans_ptr) @@ -1399,6 +1420,20 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) */ clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); + /* We shouldn't have any UIDs still set. Loop over all the UIDs to + * make sure there's nothing left there and warn if any is found. + */ + if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { + int i; + + for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) { + if (WARN_ONCE(mvm->scan_uid[i], + "UMAC scan UID %d was not cleaned\n", + mvm->scan_uid[i])) + mvm->scan_uid[i] = 0; + } + } + mvm->ucode_loaded = false; } @@ -1595,9 +1630,33 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif); if (tfd_msk) { + /* + * mac80211 first removes all the stations of the vif and + * then removes the vif. When it removes a station it also + * flushes the AMPDU session. So by now, all the AMPDU sessions + * of all the stations of this vif are closed, and the queues + * of these AMPDU sessions are properly closed. + * We still need to take care of the shared queues of the vif. + * Flush them here. + */ mutex_lock(&mvm->mutex); iwl_mvm_flush_tx_path(mvm, tfd_msk, true); mutex_unlock(&mvm->mutex); + + /* + * There are transports that buffer a few frames in the host. + * For these, the flush above isn't enough since while we were + * flushing, the transport might have sent more frames to the + * device. To solve this, wait here until the transport is + * empty. Technically, this could have replaced the flush + * above, but flush is much faster than draining. So flush + * first, and drain to make sure we have no frames in the + * transport anymore. + * If a station still had frames on the shared queues, it is + * already marked as draining, so to complete the draining, we + * just need to wait until the transport is empty. + */ + iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_msk); } if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { @@ -2167,8 +2226,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (iwl_mvm_phy_ctx_count(mvm) > 1) iwl_mvm_teardown_tdls_peers(mvm); - mutex_unlock(&mvm->mutex); - return 0; + goto out_unlock; out_quota_failed: iwl_mvm_power_update_mac(mvm); @@ -3022,6 +3080,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, duration, type); + flush_work(&mvm->roc_done_wk); + mutex_lock(&mvm->mutex); switch (vif->type) { @@ -3646,11 +3706,12 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); + mvmvif->csa_failed = false; + IWL_DEBUG_MAC80211(mvm, "pre CSA to freq %d\n", chsw->chandef.center_freq1); - iwl_fw_dbg_trigger_simple_stop(mvm, vif, FW_DBG_TRIGGER_CHANNEL_SWITCH, - NULL, 0); + iwl_fw_dbg_trigger_simple_stop(mvm, vif, FW_DBG_TRIGGER_CHANNEL_SWITCH); switch (vif->type) { case NL80211_IFTYPE_AP: @@ -3721,6 +3782,12 @@ static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); + if (mvmvif->csa_failed) { + mvmvif->csa_failed = false; + ret = -EIO; + goto out_unlock; + } + if (vif->type == NL80211_IFTYPE_STATION) { struct iwl_mvm_sta *mvmsta; @@ -3844,6 +3911,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, mvm->radio_stats.on_time_scan; do_div(survey->time_scan, USEC_PER_MSEC); + ret = 0; out: mutex_unlock(&mvm->mutex); return ret; @@ -3889,6 +3957,64 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct ieee80211_event *event) +{ +#define CHECK_MLME_TRIGGER(_mvm, _trig, _buf, _cnt, _fmt...) \ + do { \ + if ((_cnt) && --(_cnt)) \ + break; \ + iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt);\ + } while (0) + + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_fw_dbg_trigger_tlv *trig; + struct iwl_fw_dbg_trigger_mlme *trig_mlme; + + if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME)) + return; + + if (event->u.mlme.status == MLME_SUCCESS) + return; + + trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME); + trig_mlme = (void *)trig->data; + if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig)) + return; + + if (event->u.mlme.data == ASSOC_EVENT) { + if (event->u.mlme.status == MLME_DENIED) + CHECK_MLME_TRIGGER(mvm, trig, buf, + trig_mlme->stop_assoc_denied, + "DENIED ASSOC: reason %d", + event->u.mlme.reason); + else if (event->u.mlme.status == MLME_TIMEOUT) + CHECK_MLME_TRIGGER(mvm, trig, buf, + trig_mlme->stop_assoc_timeout, + "ASSOC TIMEOUT"); + } else if (event->u.mlme.data == AUTH_EVENT) { + if (event->u.mlme.status == MLME_DENIED) + CHECK_MLME_TRIGGER(mvm, trig, buf, + trig_mlme->stop_auth_denied, + "DENIED AUTH: reason %d", + event->u.mlme.reason); + else if (event->u.mlme.status == MLME_TIMEOUT) + CHECK_MLME_TRIGGER(mvm, trig, buf, + trig_mlme->stop_auth_timeout, + "AUTH TIMEOUT"); + } else if (event->u.mlme.data == DEAUTH_RX_EVENT) { + CHECK_MLME_TRIGGER(mvm, trig, buf, + trig_mlme->stop_rx_deauth, + "DEAUTH RX %d", event->u.mlme.reason); + } else if (event->u.mlme.data == DEAUTH_TX_EVENT) { + CHECK_MLME_TRIGGER(mvm, trig, buf, + trig_mlme->stop_tx_deauth, + "DEAUTH TX %d", event->u.mlme.reason); + } +#undef CHECK_MLME_TRIGGER +} + const struct ieee80211_ops iwl_mvm_hw_ops = { .tx = iwl_mvm_mac_tx, .ampdu_action = iwl_mvm_mac_ampdu_action, @@ -3942,6 +4068,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch, .tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch, + .event_callback = iwl_mvm_mac_event_callback, + CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4b5c8f66df8b..d5522a161242 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -349,11 +349,12 @@ struct iwl_mvm_vif_bf_data { * @bcast_sta: station used for broadcast packets. Used by the following * vifs: P2P_DEVICE, GO and AP. * @beacon_skb: the skb used to hold the AP/GO beacon template - * @smps_requests: the SMPS requests of differents parts of the driver, + * @smps_requests: the SMPS requests of different parts of the driver, * combined on update to yield the overall request to mac80211. * @beacon_stats: beacon statistics, containing the # of received beacons, * # of received beacons accumulated over FW restart, and the current * average signal of beacons retrieved from the firmware + * @csa_failed: CSA failed to schedule time event, report an error later */ struct iwl_mvm_vif { struct iwl_mvm *mvm; @@ -433,6 +434,7 @@ struct iwl_mvm_vif { /* Indicates that CSA countdown may be started */ bool csa_countdown; + bool csa_failed; }; static inline struct iwl_mvm_vif * @@ -686,7 +688,7 @@ struct iwl_mvm { bool disable_power_off; bool disable_power_off_d3; - bool scan_iter_notif_enabled; + u32 scan_iter_notif_enabled; /* must be u32 for debugfs_create_bool */ struct debugfs_blob_wrapper nvm_hw_blob; struct debugfs_blob_wrapper nvm_sw_blob; @@ -746,6 +748,7 @@ struct iwl_mvm { void *d3_resume_sram; u32 d3_test_pme_ptr; struct ieee80211_vif *keep_vif; + u32 last_netdetect_scans; /* no. of scans in the last net-detect wake */ #endif #endif @@ -934,7 +937,8 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) static inline bool iwl_mvm_is_wifi_mcc_supported(struct iwl_mvm *mvm) { - return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WIFI_MCC_UPDATE; + return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WIFI_MCC_UPDATE || + mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC; } static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) @@ -1146,6 +1150,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, bool force_upload, int iwl_mvm_scan_size(struct iwl_mvm *mvm); int iwl_mvm_cancel_scan(struct iwl_mvm *mvm); int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan); +void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm); /* Scheduled scan */ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, @@ -1475,8 +1480,12 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm); int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trigger, - const char *str, size_t len); - + const char *fmt, ...) __printf(3, 4); +unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool tdls, bool cmd_q); +void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + const char *errmsg); static inline bool iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig, struct ieee80211_vif *vif) @@ -1509,8 +1518,7 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm, static inline void iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_fw_dbg_trigger trig, - const char *str, size_t len) + enum iwl_fw_dbg_trigger trig) { struct iwl_fw_dbg_trigger_tlv *trigger; @@ -1521,7 +1529,7 @@ iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm, if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger)) return; - iwl_mvm_fw_dbg_collect_trig(mvm, trigger, str, len); + iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL); } #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 123e0a16aea8..87b2a30a2308 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -77,8 +77,7 @@ /* Default NVM size to read */ #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) #define IWL_MAX_NVM_SECTION_SIZE 0x1b58 -#define IWL_MAX_NVM_8000A_SECTION_SIZE 0xffc -#define IWL_MAX_NVM_8000B_SECTION_SIZE 0x1ffc +#define IWL_MAX_NVM_8000_SECTION_SIZE 0x1ffc #define NVM_WRITE_OPCODE 1 #define NVM_READ_OPCODE 0 @@ -267,7 +266,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) { struct iwl_nvm_section *sections = mvm->nvm_sections; const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; - bool is_family_8000_a_step = false, lar_enabled; + bool lar_enabled; u32 mac_addr0, mac_addr1; /* Checking for required sections */ @@ -293,12 +292,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) return NULL; } - if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) - is_family_8000_a_step = true; - /* PHY_SKU section is mandatory in B0 */ - if (!is_family_8000_a_step && - !mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) { + if (!mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) { IWL_ERR(mvm, "Can't parse phy_sku in B0, empty sections\n"); return NULL; @@ -327,8 +322,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, regulatory, mac_override, phy_sku, mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, - lar_enabled, is_family_8000_a_step, - mac_addr0, mac_addr1); + lar_enabled, mac_addr0, mac_addr1); } #define MAX_NVM_FILE_LEN 16384 @@ -381,10 +375,8 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) /* Maximal size depends on HW family and step */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) max_section_size = IWL_MAX_NVM_SECTION_SIZE; - else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) - max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; - else /* Family 8000 B-step or C-step */ - max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; + else + max_section_size = IWL_MAX_NVM_8000_SECTION_SIZE; /* * Obtain NVM image via request_firmware. Since we already used @@ -426,6 +418,15 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) IWL_INFO(mvm, "NVM Version %08X\n", le32_to_cpu(dword_buff[2])); IWL_INFO(mvm, "NVM Manufacturing date %08X\n", le32_to_cpu(dword_buff[3])); + + /* nvm file validation, dword_buff[2] holds the file version */ + if ((CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP && + le32_to_cpu(dword_buff[2]) < 0xE4A) || + (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP && + le32_to_cpu(dword_buff[2]) >= 0xE4A)) { + ret = -EFAULT; + goto out; + } } else { file_sec = (void *)fw_entry->data; } @@ -524,6 +525,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) int ret, section; u32 size_read = 0; u8 *nvm_buffer, *temp; + const char *nvm_file_B = mvm->cfg->default_nvm_file_B_step; + const char *nvm_file_C = mvm->cfg->default_nvm_file_C_step; if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) return -EINVAL; @@ -582,10 +585,27 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) /* load external NVM if configured */ if (mvm->nvm_file_name) { - /* move to External NVM flow */ + /* read External NVM file - take the default */ ret = iwl_mvm_read_external_nvm(mvm); - if (ret) - return ret; + if (ret) { + /* choose the nvm_file name according to the + * HW step + */ + if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == + SILICON_B_STEP) + mvm->nvm_file_name = nvm_file_B; + else + mvm->nvm_file_name = nvm_file_C; + + if (ret == -EFAULT && mvm->nvm_file_name) { + /* in case nvm file was failed try again */ + ret = iwl_mvm_read_external_nvm(mvm); + if (ret) + return ret; + } else { + return ret; + } + } } /* parse the relevant nvm sections */ @@ -786,13 +806,12 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) return 0; /* - * During HW restart, only replay the last set MCC to FW. Otherwise, + * try to replay the last set MCC to FW. If it doesn't exist, * queue an update to cfg80211 to retrieve the default alpha2 from FW. */ - if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - /* This should only be called during vif up and hold RTNL */ - return iwl_mvm_init_fw_regd(mvm); - } + retval = iwl_mvm_init_fw_regd(mvm); + if (retval != -ENOENT) + return retval; /* * Driver regulatory hint for initial update, this also informs the diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 80121e41ca22..a08b03d58d4b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -488,8 +488,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, /* Set a short watchdog for the command queue */ trans_cfg.cmd_q_wdg_timeout = - iwlmvm_mod_params.tfd_q_hang_detect ? IWL_DEF_WD_TIMEOUT : - IWL_WATCHDOG_DISABLED; + iwl_mvm_get_wd_timeout(mvm, NULL, false, true); snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), @@ -524,12 +523,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, /* set the nvm_file_name according to priority */ if (iwlwifi_mod_params.nvm_file) { mvm->nvm_file_name = iwlwifi_mod_params.nvm_file; - } else { - if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) && - (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) - mvm->nvm_file_name = mvm->cfg->default_nvm_file_8000A; + } else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + if (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP) + mvm->nvm_file_name = mvm->cfg->default_nvm_file_B_step; else - mvm->nvm_file_name = mvm->cfg->default_nvm_file; + mvm->nvm_file_name = mvm->cfg->default_nvm_file_C_step; } if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name, @@ -691,7 +689,6 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, { struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_cmd *cmds_trig; - char buf[32]; int i; if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF)) @@ -711,9 +708,9 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd) continue; - memset(buf, 0, sizeof(buf)); - snprintf(buf, sizeof(buf), "CMD 0x%02x received", pkt->hdr.cmd); - iwl_mvm_fw_dbg_collect_trig(mvm, trig, buf, sizeof(buf)); + iwl_mvm_fw_dbg_collect_trig(mvm, trig, + "CMD 0x%02x received", + pkt->hdr.cmd); break; } } @@ -894,18 +891,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * the next start() call from mac80211. If restart isn't called * (no fw restart) scan status will stay busy. */ - switch (mvm->scan_status) { - case IWL_MVM_SCAN_NONE: - break; - case IWL_MVM_SCAN_OS: - ieee80211_scan_completed(mvm->hw, true); - break; - case IWL_MVM_SCAN_SCHED: - /* Sched scan will be restarted by mac80211 in restart_hw. */ - if (!mvm->restart_fw) - ieee80211_sched_scan_stopped(mvm->hw); - break; - } + iwl_mvm_report_scan_aborted(mvm); /* * If we're restarting already, don't cycle restarts. @@ -1175,7 +1161,7 @@ static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc && mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) - ieee80211_connection_loss(vif); + iwl_mvm_connection_loss(mvm, vif, "D0i3"); } void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 192b74bc8cf6..e68a475e3071 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -67,7 +67,7 @@ #include "fw-api.h" #include "mvm.h" -/* Maps the driver specific channel width definition to the the fw values */ +/* Maps the driver specific channel width definition to the fw values */ u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) { switch (chandef->width) { diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 9140b0b701c7..f9928f2c125f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1277,9 +1277,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, info->status.ampdu_ack_len); } } else { - /* - * For legacy, update frame history with for each Tx retry. - */ + /* For legacy, update frame history with for each Tx retry. */ retries = info->status.rates[0].count - 1; /* HW doesn't send more than 15 retries */ retries = min(retries, 15); @@ -1615,9 +1613,9 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) static void rs_update_rate_tbl(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, - struct rs_rate *rate) + struct iwl_scale_tbl_info *tbl) { - rs_fill_lq_cmd(mvm, sta, lq_sta, rate); + rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate); iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); } @@ -2147,7 +2145,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, rate->type = LQ_NONE; lq_sta->search_better_tbl = 0; tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate); + rs_update_rate_tbl(mvm, sta, lq_sta, tbl); } return; } @@ -2310,7 +2308,7 @@ lq_update: /* Replace uCode's rate table for the destination station. */ if (update_lq) { tbl->rate.index = index; - rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate); + rs_update_rate_tbl(mvm, sta, lq_sta, tbl); } rs_stay_in_table(lq_sta, false); @@ -2357,8 +2355,7 @@ lq_update: rs_dump_rate(mvm, &tbl->rate, "Switch to SEARCH TABLE:"); - rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate); - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); + rs_update_rate_tbl(mvm, sta, lq_sta, tbl); } else { done_search = 1; } @@ -3238,7 +3235,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize; /* - * In case of low latency, tell the firwmare to leave a frame in the + * In case of low latency, tell the firmware to leave a frame in the * Tx Fifo so that it can start a transaction in the same TxOP. This * basically allows the firmware to send bursts. */ @@ -3745,7 +3742,7 @@ void iwl_mvm_rate_control_unregister(void) /** * iwl_mvm_tx_protection - Gets LQ command, change it to enable/disable - * Tx protection, according to this rquest and previous requests, + * Tx protection, according to this request and previous requests, * and send the LQ command. * @mvmsta: The station * @enable: Enable Tx protection? diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 6177e24f4c01..78ec7db64ba5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -362,7 +362,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif, trig); if (trig_check && rx_status->signal < rssi) - iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL, 0); + iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); } } @@ -552,7 +552,7 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) if (le32_to_cpup((__le32 *) (pkt->data + trig_offset)) < trig_thold) return; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL, 0); + iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); } void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index a75bb150ea27..74e1c86289dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -935,6 +935,8 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, cmd->n_channels = (u8)req->n_channels; + cmd->delay = cpu_to_le32(req->delay); + if (iwl_mvm_scan_pass_all(mvm, req)) flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; else @@ -1177,6 +1179,18 @@ static bool iwl_mvm_find_scan_type(struct iwl_mvm *mvm, return false; } +static int iwl_mvm_find_first_scan(struct iwl_mvm *mvm, + enum iwl_umac_scan_uid_type type) +{ + int i; + + for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) + if (mvm->scan_uid[i] & type) + return i; + + return i; +} + static u32 iwl_generate_scan_uid(struct iwl_mvm *mvm, enum iwl_umac_scan_uid_type type) { @@ -1436,7 +1450,13 @@ int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cpu_to_le16(req->interval / MSEC_PER_SEC); sec_part->schedule[0].iter_count = 0xff; - sec_part->delay = 0; + if (req->delay > U16_MAX) { + IWL_DEBUG_SCAN(mvm, + "delay value is > 16-bits, set to max possible\n"); + sec_part->delay = cpu_to_le16(U16_MAX); + } else { + sec_part->delay = cpu_to_le16(req->delay); + } iwl_mvm_build_unified_scan_probe(mvm, vif, ies, &sec_part->preq, req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? @@ -1613,3 +1633,54 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm) mvm->fw->ucode_capa.n_scan_channels + sizeof(struct iwl_scan_probe_req); } + +/* + * This function is used in nic restart flow, to inform mac80211 about scans + * that was aborted by restart flow or by an assert. + */ +void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) +{ + if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { + u32 uid, i; + + uid = iwl_mvm_find_first_scan(mvm, IWL_UMAC_SCAN_UID_REG_SCAN); + if (uid < IWL_MVM_MAX_SIMULTANEOUS_SCANS) { + ieee80211_scan_completed(mvm->hw, true); + mvm->scan_uid[uid] = 0; + } + uid = iwl_mvm_find_first_scan(mvm, + IWL_UMAC_SCAN_UID_SCHED_SCAN); + if (uid < IWL_MVM_MAX_SIMULTANEOUS_SCANS && !mvm->restart_fw) { + ieee80211_sched_scan_stopped(mvm->hw); + mvm->scan_uid[uid] = 0; + } + + /* We shouldn't have any UIDs still set. Loop over all the + * UIDs to make sure there's nothing left there and warn if + * any is found. + */ + for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) { + if (WARN_ONCE(mvm->scan_uid[i], + "UMAC scan UID %d was not cleaned\n", + mvm->scan_uid[i])) + mvm->scan_uid[i] = 0; + } + } else { + switch (mvm->scan_status) { + case IWL_MVM_SCAN_NONE: + break; + case IWL_MVM_SCAN_OS: + ieee80211_scan_completed(mvm->hw, true); + break; + case IWL_MVM_SCAN_SCHED: + /* + * Sched scan will be restarted by mac80211 in + * restart_hw, so do not report if FW is about to be + * restarted. + */ + if (!mvm->restart_fw) + ieee80211_sched_scan_stopped(mvm->hw); + break; + } + } +} diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 50f9288368af..1845b79487c8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -209,9 +209,8 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, { unsigned long used_hw_queues; struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? - mvm->cfg->base_params->wd_timeout : - IWL_WATCHDOG_DISABLED; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, NULL, true, false); u32 ac; lockdep_assert_held(&mvm->mutex); @@ -491,8 +490,18 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (vif->type == NL80211_IFTYPE_STATION && mvmvif->ap_sta_id == mvm_sta->sta_id) { + ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); + if (ret) + return ret; /* flush its queues here since we are freeing mvm_sta */ ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true); + if (ret) + return ret; + ret = iwl_trans_wait_tx_queue_empty(mvm->trans, + mvm_sta->tfd_queue_msk); + if (ret) + return ret; + ret = iwl_mvm_drain_sta(mvm, mvm_sta, false); /* if we are associated - we can't remove the AP STA now */ if (vif->bss_conf.assoc) @@ -971,9 +980,8 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; - unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? - mvm->cfg->base_params->wd_timeout : - IWL_WATCHDOG_DISABLED; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, vif, sta->tdls, false); int queue, fifo, ret; u16 ssn; @@ -1120,8 +1128,12 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, spin_unlock_bh(&mvmsta->lock); if (old_state >= IWL_AGG_ON) { + iwl_mvm_drain_sta(mvm, mvmsta, true); if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + iwl_trans_wait_tx_queue_empty(mvm->trans, + mvmsta->tfd_queue_msk); + iwl_mvm_drain_sta(mvm, mvmsta, false); iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); @@ -1702,8 +1714,8 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, mvm_sta->disable_tx = disable; /* - * Tell mac80211 to start/stop queueing tx for this station, - * but don't stop queueing if there are still pending frames + * Tell mac80211 to start/stop queuing tx for this station, + * but don't stop queuing if there are still pending frames * for this station. */ if (disable || !atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index d8f48975ad08..748f5dc3f9f4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -150,7 +150,7 @@ struct iwl_mvm_vif; * DOC: station table - AP Station in STA mode * * %iwl_mvm_vif includes the index of the AP station in the fw's STA table: - * %ap_sta_id. To get the point to the coresponsding %ieee80211_sta, + * %ap_sta_id. To get the point to the corresponding %ieee80211_sta, * &fw_id_to_mac_id can be used. Due to the way the fw works, we must not remove * the AP station from the fw before setting the MAC context as unassociated. * Hence, %fw_id_to_mac_id[%ap_sta_id] will be NULLed when the AP station is @@ -209,14 +209,14 @@ struct iwl_mvm_vif; * When a trigger frame is received, mac80211 tells the driver to send frames * from the AMPDU queues or sends frames to non-aggregation queues itself, * depending on which ACs are delivery-enabled and what TID has frames to - * transmit. Note that mac80211 has all the knowledege since all the non-agg + * transmit. Note that mac80211 has all the knowledge since all the non-agg * frames are buffered / filtered, and the driver tells mac80211 about agg * frames). The driver needs to tell the fw to let frames out even if the * station is asleep. This is done by %iwl_mvm_sta_modify_sleep_tx_count. * * When we receive a frame from that station with PM bit unset, the driver * needs to let the fw know that this station isn't asleep any more. This is - * done by %iwl_mvm_sta_modify_ps_wake in response to mac80211 signalling the + * done by %iwl_mvm_sta_modify_ps_wake in response to mac80211 signaling the * station's wakeup. * * For a GO, the Service Period might be cut short due to an absence period diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 8d179ab67cc2..fd7b0d36f9a6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -119,7 +119,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) /* * Flush the offchannel queue -- this is called when the time - * event finishes or is cancelled, so that frames queued for it + * event finishes or is canceled, so that frames queued for it * won't get stuck on the queue and be transmitted in the next * time event. * We have to send the command asynchronously since this cannot @@ -187,7 +187,8 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, return false; if (errmsg) IWL_ERR(mvm, "%s\n", errmsg); - ieee80211_connection_loss(vif); + + iwl_mvm_connection_loss(mvm, vif, errmsg); return true; } @@ -196,19 +197,24 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, struct iwl_mvm_time_event_data *te_data, struct iwl_time_event_notif *notif) { - if (!le32_to_cpu(notif->status)) { - if (te_data->vif->type == NL80211_IFTYPE_STATION) - ieee80211_connection_loss(te_data->vif); + struct ieee80211_vif *vif = te_data->vif; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (!notif->status) IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); - iwl_mvm_te_clear_data(mvm, te_data); - return; - } switch (te_data->vif->type) { case NL80211_IFTYPE_AP: + if (!notif->status) + mvmvif->csa_failed = true; iwl_mvm_csa_noa_start(mvm); break; case NL80211_IFTYPE_STATION: + if (!notif->status) { + iwl_mvm_connection_loss(mvm, vif, + "CSA TE failed to start"); + break; + } iwl_mvm_csa_client_absent(mvm, te_data->vif); ieee80211_chswitch_done(te_data->vif, true); break; @@ -222,6 +228,44 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, iwl_mvm_te_clear_data(mvm, te_data); } +static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm, + struct iwl_time_event_notif *notif, + struct iwl_mvm_time_event_data *te_data) +{ + struct iwl_fw_dbg_trigger_tlv *trig; + struct iwl_fw_dbg_trigger_time_event *te_trig; + int i; + + if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT)) + return; + + trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT); + te_trig = (void *)trig->data; + + if (!iwl_fw_dbg_trigger_check_stop(mvm, te_data->vif, trig)) + return; + + for (i = 0; i < ARRAY_SIZE(te_trig->time_events); i++) { + u32 trig_te_id = le32_to_cpu(te_trig->time_events[i].id); + u32 trig_action_bitmap = + le32_to_cpu(te_trig->time_events[i].action_bitmap); + u32 trig_status_bitmap = + le32_to_cpu(te_trig->time_events[i].status_bitmap); + + if (trig_te_id != te_data->id || + !(trig_action_bitmap & le32_to_cpu(notif->action)) || + !(trig_status_bitmap & BIT(le32_to_cpu(notif->status)))) + continue; + + iwl_mvm_fw_dbg_collect_trig(mvm, trig, + "Time event %d Action 0x%x received status: %d", + te_data->id, + le32_to_cpu(notif->action), + le32_to_cpu(notif->status)); + break; + } +} + /* * Handles a FW notification for an event that is known to the driver. * @@ -239,6 +283,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, le32_to_cpu(notif->unique_id), le32_to_cpu(notif->action)); + iwl_mvm_te_check_trigger(mvm, notif, te_data); + /* * The FW sends the start/end time event notifications even for events * that it fails to schedule. This is indicated in the status field of @@ -248,11 +294,16 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * events in the system). */ if (!le32_to_cpu(notif->status)) { - bool start = le32_to_cpu(notif->action) & - TE_V2_NOTIF_HOST_EVENT_START; - IWL_WARN(mvm, "Time Event %s notification failure\n", - start ? "start" : "end"); - if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, NULL)) { + const char *msg; + + if (notif->action & cpu_to_le32(TE_V2_NOTIF_HOST_EVENT_START)) + msg = "Time Event start notification failure"; + else + msg = "Time Event end notification failure"; + + IWL_DEBUG_TE(mvm, "%s\n", msg); + + if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, msg)) { iwl_mvm_te_clear_data(mvm, te_data); return; } @@ -315,6 +366,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, if (!aux_roc_te) /* Not a Aux ROC time event */ return -EINVAL; + iwl_mvm_te_check_trigger(mvm, notif, te_data); + if (!le32_to_cpu(notif->status)) { IWL_DEBUG_TE(mvm, "ERROR: Aux ROC Time Event %s notification failure\n", @@ -769,7 +822,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm) * Iterate over the list of aux roc time events and find the time * event that is associated with a BSS interface. * This assumes that a BSS interface can have only a single time - * event at any given time and this time event coresponds to a ROC + * event at any given time and this time event corresponds to a ROC * request */ list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) { diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index 6f6b35db3ab8..de4fbc6d57f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -147,7 +147,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, * @vif: the virtual interface for which the session is issued * * This functions cancels the session protection which is an act of good - * citizenship. If it is not needed any more it should be cancelled because + * citizenship. If it is not needed any more it should be canceled because * the other bindings wait for the medium during that time. * This funtions doesn't sleep. */ @@ -162,7 +162,7 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, struct iwl_device_cmd *cmd); /** - * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionlity + * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionality * @mvm: the mvm component * @vif: the virtual interface for which the roc is requested. It is assumed * that the vif type is NL80211_IFTYPE_P2P_DEVICE diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index ba34dda1ae36..ef32e177f662 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -1049,6 +1049,14 @@ out: return 0; } +/* + * Note that there are transports that buffer frames before they reach + * the firmware. This means that after flush_tx_path is called, the + * queue might not be empty. The race-free way to handle this is to: + * 1) set the station as draining + * 2) flush the Tx path + * 3) wait for the transport queues to be empty + */ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync) { int ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 435faee0a28e..bc55a8b82db6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -122,7 +122,7 @@ int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, } /* - * We assume that the caller set the status to the sucess value + * We assume that the caller set the status to the success value */ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, u32 *status) @@ -737,7 +737,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init) } /** - * iwl_mvm_update_smps - Get a requst to change the SMPS mode + * iwl_mvm_update_smps - Get a request to change the SMPS mode * @req_type: The part of the driver who call for a change. * @smps_requests: The request to change the SMPS mode. * @@ -921,3 +921,71 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm) return bss_iter_data.vif; } + +unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool tdls, bool cmd_q) +{ + struct iwl_fw_dbg_trigger_tlv *trigger; + struct iwl_fw_dbg_trigger_txq_timer *txq_timer; + unsigned int default_timeout = + cmd_q ? IWL_DEF_WD_TIMEOUT : mvm->cfg->base_params->wd_timeout; + + if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS)) + return iwlmvm_mod_params.tfd_q_hang_detect ? + default_timeout : IWL_WATCHDOG_DISABLED; + + trigger = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS); + txq_timer = (void *)trigger->data; + + if (tdls) + return le32_to_cpu(txq_timer->tdls); + + if (cmd_q) + return le32_to_cpu(txq_timer->command_queue); + + if (WARN_ON(!vif)) + return default_timeout; + + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_ADHOC: + return le32_to_cpu(txq_timer->ibss); + case NL80211_IFTYPE_STATION: + return le32_to_cpu(txq_timer->bss); + case NL80211_IFTYPE_AP: + return le32_to_cpu(txq_timer->softap); + case NL80211_IFTYPE_P2P_CLIENT: + return le32_to_cpu(txq_timer->p2p_client); + case NL80211_IFTYPE_P2P_GO: + return le32_to_cpu(txq_timer->p2p_go); + case NL80211_IFTYPE_P2P_DEVICE: + return le32_to_cpu(txq_timer->p2p_device); + default: + WARN_ON(1); + return mvm->cfg->base_params->wd_timeout; + } +} + +void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + const char *errmsg) +{ + struct iwl_fw_dbg_trigger_tlv *trig; + struct iwl_fw_dbg_trigger_mlme *trig_mlme; + + if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME)) + goto out; + + trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME); + trig_mlme = (void *)trig->data; + if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig)) + goto out; + + if (trig_mlme->stop_connection_loss && + --trig_mlme->stop_connection_loss) + goto out; + + iwl_mvm_fw_dbg_collect_trig(mvm, trig, "%s", errmsg); + +out: + ieee80211_connection_loss(vif); +} diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 7b7e2f223fb2..7ff69c642103 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -600,9 +600,11 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) break; - IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n", - rxcb._offset, get_cmd_string(trans_pcie, pkt->hdr.cmd), - pkt->hdr.cmd); + IWL_DEBUG_RX(trans, + "cmd at offset %d: %s (0x%.2x, seq 0x%x)\n", + rxcb._offset, + get_cmd_string(trans_pcie, pkt->hdr.cmd), + pkt->hdr.cmd, le16_to_cpu(pkt->hdr.sequence)); len = iwl_rx_packet_len(pkt); len += sizeof(u32); /* account for status word */ diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index dc247325d8d7..2de8fbfe4edf 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -691,11 +691,15 @@ static int iwl_pcie_rsa_race_bug_wa(struct iwl_trans *trans) { u32 val, loop = 1000; - /* Check the RSA semaphore is accessible - if not, we are in trouble */ + /* + * Check the RSA semaphore is accessible. + * If the HW isn't locked and the rsa semaphore isn't accessible, + * we are in trouble. + */ val = iwl_read_prph(trans, PREG_AUX_BUS_WPROT_0); if (val & (BIT(1) | BIT(17))) { - IWL_ERR(trans, - "can't access the RSA semaphore it is write protected\n"); + IWL_INFO(trans, + "can't access the RSA semaphore it is write protected\n"); return 0; } @@ -719,10 +723,10 @@ static int iwl_pcie_rsa_race_bug_wa(struct iwl_trans *trans) return -EIO; } -static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans, - const struct fw_img *image, - int cpu, - int *first_ucode_section) +static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, + const struct fw_img *image, + int cpu, + int *first_ucode_section) { int shift_param; int i, ret = 0, sec_num = 0x1; @@ -917,20 +921,16 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, } /* release CPU reset */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) - iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); - else - iwl_write32(trans, CSR_RESET, 0); + iwl_write32(trans, CSR_RESET, 0); return 0; } -static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, - const struct fw_img *image) +static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, + const struct fw_img *image) { int ret = 0; int first_ucode_section; - u32 reg; IWL_DEBUG_FW(trans, "working with %s CPU\n", image->is_dual_cpus ? "Dual" : "Single"); @@ -948,38 +948,23 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); /* load to FW the binary Secured sections of CPU1 */ - ret = iwl_pcie_load_cpu_sections_8000b(trans, image, 1, - &first_ucode_section); + ret = iwl_pcie_load_cpu_sections_8000(trans, image, 1, + &first_ucode_section); if (ret) return ret; /* load to FW the binary sections of CPU2 */ - ret = iwl_pcie_load_cpu_sections_8000b(trans, image, 2, - &first_ucode_section); + ret = iwl_pcie_load_cpu_sections_8000(trans, image, 2, + &first_ucode_section); if (ret) return ret; - /* wait for image verification to complete */ - ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0, - LMPM_SECURE_BOOT_STATUS_SUCCESS, - LMPM_SECURE_BOOT_STATUS_SUCCESS, - LMPM_SECURE_TIME_OUT); - if (ret < 0) { - reg = iwl_read_prph(trans, - LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0); - - IWL_ERR(trans, "Timeout on secure boot process, reg = %x\n", - reg); - return ret; - } - return 0; } static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; bool hw_rfkill; @@ -1009,9 +994,6 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, return ret; } - /* init ref_count to 1 (should be cleared when ucode is loaded) */ - trans_pcie->ref_count = 1; - /* make sure rfkill handshake bits are cleared */ iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, @@ -1026,9 +1008,8 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); /* Load the given image to the HW */ - if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) && - (CSR_HW_REV_STEP(trans->hw_rev) != SILICON_A_STEP)) - return iwl_pcie_load_given_ucode_8000b(trans, fw); + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + return iwl_pcie_load_given_ucode_8000(trans, fw); else return iwl_pcie_load_given_ucode(trans, fw); } @@ -1330,6 +1311,9 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; trans_pcie->scd_set_active = trans_cfg->scd_set_active; + /* init ref_count to 1 (should be cleared when ucode is loaded) */ + trans_pcie->ref_count = 1; + /* Initialize NAPI here - it should be before registering to mac80211 * in the opmode but after the HW struct is allocated. * As this function may be called again in some corner cases don't diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 074f716020aa..01f56c7df8b5 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -1315,7 +1315,8 @@ static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc) } /*should call before software enc*/ -u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, + bool is_enc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -1344,7 +1345,9 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) break; } - offset = mac_hdr_len + SNAP_SIZE + encrypt_header_len; + offset = mac_hdr_len + SNAP_SIZE; + if (is_enc) + offset += encrypt_header_len; ether_type = be16_to_cpup((__be16 *)(skb->data + offset)); if (ETH_P_IP == ether_type) { diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index ff9a4bfd4515..74233d601a90 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -120,7 +120,8 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, bool isvht, u8 desc_rate); bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); -u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, + bool is_enc); void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb); int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 8c45cf44ce24..f46c9d7f6528 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -887,7 +887,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) unicast = true; rtlpriv->stats.rxbytesunicast += skb->len; } - rtl_is_special_data(hw, skb, false); + rtl_is_special_data(hw, skb, false, true); if (ieee80211_is_data(fc)) { rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index 7863bd278b22..74c14ce28238 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -56,7 +56,8 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, wireless_mode = sta_entry->wireless_mode; } - if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) || not_data) { + if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true, false) || + not_data) { return 0; } else { if (rtlhal->current_bandtype == BAND_ON_2_4G) { @@ -201,7 +202,7 @@ static void rtl_tx_status(void *ppriv, if (!priv_sta || !ieee80211_is_data(fc)) return; - if (rtl_is_special_data(mac->hw, skb, true)) + if (rtl_is_special_data(mac->hw, skb, true, true)) return; if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index d1e9a13be910..5d54d16a59e7 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1608,7 +1608,7 @@ int wl1251_free_hw(struct wl1251 *wl) } EXPORT_SYMBOL_GPL(wl1251_free_hw); -MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); +MODULE_DESCRIPTION("TI wl1251 Wireless LAN Driver Core"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); MODULE_FIRMWARE(WL1251_FW_NAME); diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 7929fac13e1c..107714e4405f 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -73,4 +73,5 @@ source "drivers/nfc/microread/Kconfig" source "drivers/nfc/nfcmrvl/Kconfig" source "drivers/nfc/st21nfca/Kconfig" source "drivers/nfc/st21nfcb/Kconfig" +source "drivers/nfc/nxp-nci/Kconfig" endmenu diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 6b23a2c6e34a..a4292d790f9b 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -13,5 +13,6 @@ obj-$(CONFIG_NFC_MRVL) += nfcmrvl/ obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/ +obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/ ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c index df85cd3d9db0..661e2c8143c4 100644 --- a/drivers/nfc/microread/i2c.c +++ b/drivers/nfc/microread/i2c.c @@ -286,7 +286,7 @@ static int microread_i2c_probe(struct i2c_client *client, if (r < 0) goto err_irq; - nfc_info(&client->dev, "Probed"); + nfc_info(&client->dev, "Probed\n"); return 0; diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c index 85e8bcf98693..ad4933cefbd1 100644 --- a/drivers/nfc/nfcmrvl/main.c +++ b/drivers/nfc/nfcmrvl/main.c @@ -111,7 +111,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0); if (!priv->ndev) { - nfc_err(dev, "nci_allocate_device failed"); + nfc_err(dev, "nci_allocate_device failed\n"); rc = -ENOMEM; goto error; } @@ -120,7 +120,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, rc = nci_register_device(priv->ndev); if (rc) { - nfc_err(dev, "nci_register_device failed %d", rc); + nfc_err(dev, "nci_register_device failed %d\n", rc); nci_free_device(priv->ndev); goto error; } diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c index 3221ca37d6c9..6cf15c1a2618 100644 --- a/drivers/nfc/nfcmrvl/usb.c +++ b/drivers/nfc/nfcmrvl/usb.c @@ -80,7 +80,7 @@ static void nfcmrvl_bulk_complete(struct urb *urb) if (!urb->status) { if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer, urb->actual_length) < 0) - nfc_err(&drv_data->udev->dev, "corrupted Rx packet"); + nfc_err(&drv_data->udev->dev, "corrupted Rx packet\n"); } if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) @@ -96,7 +96,7 @@ static void nfcmrvl_bulk_complete(struct urb *urb) */ if (err != -EPERM && err != -ENODEV) nfc_err(&drv_data->udev->dev, - "urb %p failed to resubmit (%d)", urb, -err); + "urb %p failed to resubmit (%d)\n", urb, -err); usb_unanchor_urb(urb); } } @@ -137,7 +137,7 @@ nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags) if (err) { if (err != -EPERM && err != -ENODEV) nfc_err(&drv_data->udev->dev, - "urb %p submission failed (%d)", urb, -err); + "urb %p submission failed (%d)\n", urb, -err); usb_unanchor_urb(urb); } @@ -153,7 +153,7 @@ static void nfcmrvl_tx_complete(struct urb *urb) struct nfcmrvl_private *priv = nci_get_drvdata(ndev); struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data; - nfc_info(priv->dev, "urb %p status %d count %d", + nfc_info(priv->dev, "urb %p status %d count %d\n", urb, urb->status, urb->actual_length); spin_lock(&drv_data->txlock); @@ -253,7 +253,7 @@ static int nfcmrvl_usb_nci_send(struct nfcmrvl_private *priv, if (err) { if (err != -EPERM && err != -ENODEV) nfc_err(&drv_data->udev->dev, - "urb %p submission failed (%d)", urb, -err); + "urb %p submission failed (%d)\n", urb, -err); kfree(urb->setup_packet); usb_unanchor_urb(urb); } else { @@ -293,7 +293,7 @@ static int nfcmrvl_probe(struct usb_interface *intf, int i; struct usb_device *udev = interface_to_usbdev(intf); - nfc_info(&udev->dev, "intf %p id %p", intf, id); + nfc_info(&udev->dev, "intf %p id %p\n", intf, id); drv_data = devm_kzalloc(&intf->dev, sizeof(*drv_data), GFP_KERNEL); if (!drv_data) @@ -348,7 +348,7 @@ static void nfcmrvl_disconnect(struct usb_interface *intf) if (!drv_data) return; - nfc_info(&drv_data->udev->dev, "intf %p", intf); + nfc_info(&drv_data->udev->dev, "intf %p\n", intf); nfcmrvl_nci_unregister_dev(drv_data->priv); @@ -360,7 +360,7 @@ static int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message) { struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf); - nfc_info(&drv_data->udev->dev, "intf %p", intf); + nfc_info(&drv_data->udev->dev, "intf %p\n", intf); if (drv_data->suspend_count++) return 0; @@ -401,7 +401,7 @@ static int nfcmrvl_resume(struct usb_interface *intf) struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf); int err = 0; - nfc_info(&drv_data->udev->dev, "intf %p", intf); + nfc_info(&drv_data->udev->dev, "intf %p\n", intf); if (--drv_data->suspend_count) return 0; diff --git a/drivers/nfc/nxp-nci/Kconfig b/drivers/nfc/nxp-nci/Kconfig new file mode 100644 index 000000000000..37b40612520d --- /dev/null +++ b/drivers/nfc/nxp-nci/Kconfig @@ -0,0 +1,25 @@ +config NFC_NXP_NCI + tristate "NXP-NCI NFC driver" + depends on NFC_NCI + default n + ---help--- + Generic core driver for NXP NCI chips such as the NPC100 + or PN7150 families. + This is a driver based on the NCI NFC kernel layers and + will thus not work with NXP libnfc library. + + To compile this driver as a module, choose m here. The module will + be called nxp_nci. + Say N if unsure. + +config NFC_NXP_NCI_I2C + tristate "NXP-NCI I2C support" + depends on NFC_NXP_NCI && I2C + ---help--- + This module adds support for an I2C interface to the NXP NCI + chips. + Select this if your platform is using the I2C bus. + + To compile this driver as a module, choose m here. The module will + be called nxp_nci_i2c. + Say Y if unsure. diff --git a/drivers/nfc/nxp-nci/Makefile b/drivers/nfc/nxp-nci/Makefile new file mode 100644 index 000000000000..c008be30bb18 --- /dev/null +++ b/drivers/nfc/nxp-nci/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for NXP-NCI NFC driver +# + +nxp-nci-objs = core.o firmware.o +nxp-nci_i2c-objs = i2c.o + +obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o +obj-$(CONFIG_NFC_NXP_NCI_I2C) += nxp-nci_i2c.o + +ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/nxp-nci/core.c b/drivers/nfc/nxp-nci/core.c new file mode 100644 index 000000000000..8979636d48ea --- /dev/null +++ b/drivers/nfc/nxp-nci/core.c @@ -0,0 +1,186 @@ +/* + * Generic driver for NXP NCI NFC chips + * + * Copyright (C) 2014 NXP Semiconductors All rights reserved. + * + * Authors: Clément Perrochaud <clement.perrochaud@nxp.com> + * + * Derived from PN544 device driver: + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/nfc.h> +#include <linux/platform_data/nxp-nci.h> + +#include <net/nfc/nci_core.h> + +#include "nxp-nci.h" + +#define NXP_NCI_HDR_LEN 4 + +#define NXP_NCI_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ + NFC_PROTO_MIFARE_MASK | \ + NFC_PROTO_FELICA_MASK | \ + NFC_PROTO_ISO14443_MASK | \ + NFC_PROTO_ISO14443_B_MASK | \ + NFC_PROTO_NFC_DEP_MASK) + +static int nxp_nci_open(struct nci_dev *ndev) +{ + struct nxp_nci_info *info = nci_get_drvdata(ndev); + int r = 0; + + mutex_lock(&info->info_lock); + + if (info->mode != NXP_NCI_MODE_COLD) { + r = -EBUSY; + goto open_exit; + } + + if (info->phy_ops->set_mode) + r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_NCI); + + info->mode = NXP_NCI_MODE_NCI; + +open_exit: + mutex_unlock(&info->info_lock); + return r; +} + +static int nxp_nci_close(struct nci_dev *ndev) +{ + struct nxp_nci_info *info = nci_get_drvdata(ndev); + int r = 0; + + mutex_lock(&info->info_lock); + + if (info->phy_ops->set_mode) + r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD); + + info->mode = NXP_NCI_MODE_COLD; + + mutex_unlock(&info->info_lock); + return r; +} + +static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb) +{ + struct nxp_nci_info *info = nci_get_drvdata(ndev); + int r; + + if (!info->phy_ops->write) { + r = -ENOTSUPP; + goto send_exit; + } + + if (info->mode != NXP_NCI_MODE_NCI) { + r = -EINVAL; + goto send_exit; + } + + r = info->phy_ops->write(info->phy_id, skb); + if (r < 0) + kfree_skb(skb); + +send_exit: + return r; +} + +static struct nci_ops nxp_nci_ops = { + .open = nxp_nci_open, + .close = nxp_nci_close, + .send = nxp_nci_send, + .fw_download = nxp_nci_fw_download, +}; + +int nxp_nci_probe(void *phy_id, struct device *pdev, + struct nxp_nci_phy_ops *phy_ops, unsigned int max_payload, + struct nci_dev **ndev) +{ + struct nxp_nci_info *info; + int r; + + info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL); + if (!info) { + r = -ENOMEM; + goto probe_exit; + } + + info->phy_id = phy_id; + info->pdev = pdev; + info->phy_ops = phy_ops; + info->max_payload = max_payload; + INIT_WORK(&info->fw_info.work, nxp_nci_fw_work); + init_completion(&info->fw_info.cmd_completion); + mutex_init(&info->info_lock); + + if (info->phy_ops->set_mode) { + r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD); + if (r < 0) + goto probe_exit; + } + + info->mode = NXP_NCI_MODE_COLD; + + info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS, + NXP_NCI_HDR_LEN, 0); + if (!info->ndev) { + r = -ENOMEM; + goto probe_exit; + } + + nci_set_parent_dev(info->ndev, pdev); + nci_set_drvdata(info->ndev, info); + r = nci_register_device(info->ndev); + if (r < 0) + goto probe_exit_free_nci; + + *ndev = info->ndev; + + goto probe_exit; + +probe_exit_free_nci: + nci_free_device(info->ndev); +probe_exit: + return r; +} +EXPORT_SYMBOL(nxp_nci_probe); + +void nxp_nci_remove(struct nci_dev *ndev) +{ + struct nxp_nci_info *info = nci_get_drvdata(ndev); + + if (info->mode == NXP_NCI_MODE_FW) + nxp_nci_fw_work_complete(info, -ESHUTDOWN); + cancel_work_sync(&info->fw_info.work); + + mutex_lock(&info->info_lock); + + if (info->phy_ops->set_mode) + info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD); + + nci_unregister_device(ndev); + nci_free_device(ndev); + + mutex_unlock(&info->info_lock); +} +EXPORT_SYMBOL(nxp_nci_remove); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("NXP NCI NFC driver"); +MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>"); diff --git a/drivers/nfc/nxp-nci/firmware.c b/drivers/nfc/nxp-nci/firmware.c new file mode 100644 index 000000000000..5291797324ba --- /dev/null +++ b/drivers/nfc/nxp-nci/firmware.c @@ -0,0 +1,325 @@ +/* + * Generic driver for NXP NCI NFC chips + * + * Copyright (C) 2014 NXP Semiconductors All rights reserved. + * + * Author: Clément Perrochaud <clement.perrochaud@nxp.com> + * + * Derived from PN544 device driver: + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/completion.h> +#include <linux/firmware.h> +#include <linux/nfc.h> +#include <linux/unaligned/access_ok.h> + +#include "nxp-nci.h" + +/* Crypto operations can take up to 30 seconds */ +#define NXP_NCI_FW_ANSWER_TIMEOUT msecs_to_jiffies(30000) + +#define NXP_NCI_FW_CMD_RESET 0xF0 +#define NXP_NCI_FW_CMD_GETVERSION 0xF1 +#define NXP_NCI_FW_CMD_CHECKINTEGRITY 0xE0 +#define NXP_NCI_FW_CMD_WRITE 0xC0 +#define NXP_NCI_FW_CMD_READ 0xA2 +#define NXP_NCI_FW_CMD_GETSESSIONSTATE 0xF2 +#define NXP_NCI_FW_CMD_LOG 0xA7 +#define NXP_NCI_FW_CMD_FORCE 0xD0 +#define NXP_NCI_FW_CMD_GET_DIE_ID 0xF4 + +#define NXP_NCI_FW_CHUNK_FLAG 0x0400 + +#define NXP_NCI_FW_RESULT_OK 0x00 +#define NXP_NCI_FW_RESULT_INVALID_ADDR 0x01 +#define NXP_NCI_FW_RESULT_GENERIC_ERROR 0x02 +#define NXP_NCI_FW_RESULT_UNKNOWN_CMD 0x0B +#define NXP_NCI_FW_RESULT_ABORTED_CMD 0x0C +#define NXP_NCI_FW_RESULT_PLL_ERROR 0x0D +#define NXP_NCI_FW_RESULT_ADDR_RANGE_OFL_ERROR 0x1E +#define NXP_NCI_FW_RESULT_BUFFER_OFL_ERROR 0x1F +#define NXP_NCI_FW_RESULT_MEM_BSY 0x20 +#define NXP_NCI_FW_RESULT_SIGNATURE_ERROR 0x21 +#define NXP_NCI_FW_RESULT_FIRMWARE_VERSION_ERROR 0x24 +#define NXP_NCI_FW_RESULT_PROTOCOL_ERROR 0x28 +#define NXP_NCI_FW_RESULT_SFWU_DEGRADED 0x2A +#define NXP_NCI_FW_RESULT_PH_STATUS_FIRST_CHUNK 0x2D +#define NXP_NCI_FW_RESULT_PH_STATUS_NEXT_CHUNK 0x2E +#define NXP_NCI_FW_RESULT_PH_STATUS_INTERNAL_ERROR_5 0xC5 + +void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result) +{ + struct nxp_nci_fw_info *fw_info = &info->fw_info; + int r; + + if (info->phy_ops->set_mode) { + r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD); + if (r < 0 && result == 0) + result = -r; + } + + info->mode = NXP_NCI_MODE_COLD; + + if (fw_info->fw) { + release_firmware(fw_info->fw); + fw_info->fw = NULL; + } + + nfc_fw_download_done(info->ndev->nfc_dev, fw_info->name, (u32) -result); +} + +/* crc_ccitt cannot be used since it is computed MSB first and not LSB first */ +static u16 nxp_nci_fw_crc(u8 const *buffer, size_t len) +{ + u16 crc = 0xffff; + + while (len--) { + crc = ((crc >> 8) | (crc << 8)) ^ *buffer++; + crc ^= (crc & 0xff) >> 4; + crc ^= (crc & 0xff) << 12; + crc ^= (crc & 0xff) << 5; + } + + return crc; +} + +static int nxp_nci_fw_send_chunk(struct nxp_nci_info *info) +{ + struct nxp_nci_fw_info *fw_info = &info->fw_info; + u16 header, crc; + struct sk_buff *skb; + size_t chunk_len; + size_t remaining_len; + int r; + + skb = nci_skb_alloc(info->ndev, info->max_payload, GFP_KERNEL); + if (!skb) { + r = -ENOMEM; + goto chunk_exit; + } + + chunk_len = info->max_payload - NXP_NCI_FW_HDR_LEN - NXP_NCI_FW_CRC_LEN; + remaining_len = fw_info->frame_size - fw_info->written; + + if (remaining_len > chunk_len) { + header = NXP_NCI_FW_CHUNK_FLAG; + } else { + chunk_len = remaining_len; + header = 0x0000; + } + + header |= chunk_len & NXP_NCI_FW_FRAME_LEN_MASK; + put_unaligned_be16(header, skb_put(skb, NXP_NCI_FW_HDR_LEN)); + + memcpy(skb_put(skb, chunk_len), fw_info->data + fw_info->written, + chunk_len); + + crc = nxp_nci_fw_crc(skb->data, chunk_len + NXP_NCI_FW_HDR_LEN); + put_unaligned_be16(crc, skb_put(skb, NXP_NCI_FW_CRC_LEN)); + + r = info->phy_ops->write(info->phy_id, skb); + if (r >= 0) + r = chunk_len; + + kfree_skb(skb); + +chunk_exit: + return r; +} + +static int nxp_nci_fw_send(struct nxp_nci_info *info) +{ + struct nxp_nci_fw_info *fw_info = &info->fw_info; + long completion_rc; + int r; + + reinit_completion(&fw_info->cmd_completion); + + if (fw_info->written == 0) { + fw_info->frame_size = get_unaligned_be16(fw_info->data) & + NXP_NCI_FW_FRAME_LEN_MASK; + fw_info->data += NXP_NCI_FW_HDR_LEN; + fw_info->size -= NXP_NCI_FW_HDR_LEN; + } + + if (fw_info->frame_size > fw_info->size) + return -EMSGSIZE; + + r = nxp_nci_fw_send_chunk(info); + if (r < 0) + return r; + + fw_info->written += r; + + if (*fw_info->data == NXP_NCI_FW_CMD_RESET) { + fw_info->cmd_result = 0; + if (fw_info->fw) + schedule_work(&fw_info->work); + } else { + completion_rc = wait_for_completion_interruptible_timeout( + &fw_info->cmd_completion, NXP_NCI_FW_ANSWER_TIMEOUT); + if (completion_rc == 0) + return -ETIMEDOUT; + } + + return 0; +} + +void nxp_nci_fw_work(struct work_struct *work) +{ + struct nxp_nci_info *info; + struct nxp_nci_fw_info *fw_info; + int r; + + fw_info = container_of(work, struct nxp_nci_fw_info, work); + info = container_of(fw_info, struct nxp_nci_info, fw_info); + + mutex_lock(&info->info_lock); + + r = fw_info->cmd_result; + if (r < 0) + goto exit_work; + + if (fw_info->written == fw_info->frame_size) { + fw_info->data += fw_info->frame_size; + fw_info->size -= fw_info->frame_size; + fw_info->written = 0; + } + + if (fw_info->size > 0) + r = nxp_nci_fw_send(info); + +exit_work: + if (r < 0 || fw_info->size == 0) + nxp_nci_fw_work_complete(info, r); + mutex_unlock(&info->info_lock); +} + +int nxp_nci_fw_download(struct nci_dev *ndev, const char *firmware_name) +{ + struct nxp_nci_info *info = nci_get_drvdata(ndev); + struct nxp_nci_fw_info *fw_info = &info->fw_info; + int r; + + mutex_lock(&info->info_lock); + + if (!info->phy_ops->set_mode || !info->phy_ops->write) { + r = -ENOTSUPP; + goto fw_download_exit; + } + + if (!firmware_name || firmware_name[0] == '\0') { + r = -EINVAL; + goto fw_download_exit; + } + + strcpy(fw_info->name, firmware_name); + + r = request_firmware(&fw_info->fw, firmware_name, + ndev->nfc_dev->dev.parent); + if (r < 0) + goto fw_download_exit; + + r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_FW); + if (r < 0) { + release_firmware(fw_info->fw); + goto fw_download_exit; + } + + info->mode = NXP_NCI_MODE_FW; + + fw_info->data = fw_info->fw->data; + fw_info->size = fw_info->fw->size; + fw_info->written = 0; + fw_info->frame_size = 0; + fw_info->cmd_result = 0; + + schedule_work(&fw_info->work); + +fw_download_exit: + mutex_unlock(&info->info_lock); + return r; +} + +static int nxp_nci_fw_read_status(u8 stat) +{ + switch (stat) { + case NXP_NCI_FW_RESULT_OK: + return 0; + case NXP_NCI_FW_RESULT_INVALID_ADDR: + return -EINVAL; + case NXP_NCI_FW_RESULT_UNKNOWN_CMD: + return -EINVAL; + case NXP_NCI_FW_RESULT_ABORTED_CMD: + return -EMSGSIZE; + case NXP_NCI_FW_RESULT_ADDR_RANGE_OFL_ERROR: + return -EADDRNOTAVAIL; + case NXP_NCI_FW_RESULT_BUFFER_OFL_ERROR: + return -ENOBUFS; + case NXP_NCI_FW_RESULT_MEM_BSY: + return -ENOKEY; + case NXP_NCI_FW_RESULT_SIGNATURE_ERROR: + return -EKEYREJECTED; + case NXP_NCI_FW_RESULT_FIRMWARE_VERSION_ERROR: + return -EALREADY; + case NXP_NCI_FW_RESULT_PROTOCOL_ERROR: + return -EPROTO; + case NXP_NCI_FW_RESULT_SFWU_DEGRADED: + return -EHWPOISON; + case NXP_NCI_FW_RESULT_PH_STATUS_FIRST_CHUNK: + return 0; + case NXP_NCI_FW_RESULT_PH_STATUS_NEXT_CHUNK: + return 0; + case NXP_NCI_FW_RESULT_PH_STATUS_INTERNAL_ERROR_5: + return -EINVAL; + default: + return -EIO; + } +} + +static u16 nxp_nci_fw_check_crc(struct sk_buff *skb) +{ + u16 crc, frame_crc; + size_t len = skb->len - NXP_NCI_FW_CRC_LEN; + + crc = nxp_nci_fw_crc(skb->data, len); + frame_crc = get_unaligned_be16(skb->data + len); + + return (crc ^ frame_crc); +} + +void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb) +{ + struct nxp_nci_info *info = nci_get_drvdata(ndev); + struct nxp_nci_fw_info *fw_info = &info->fw_info; + + complete(&fw_info->cmd_completion); + + if (skb) { + if (nxp_nci_fw_check_crc(skb) != 0x00) + fw_info->cmd_result = -EBADMSG; + else + fw_info->cmd_result = nxp_nci_fw_read_status( + *skb_pull(skb, NXP_NCI_FW_HDR_LEN)); + kfree_skb(skb); + } else { + fw_info->cmd_result = -EIO; + } + + if (fw_info->fw) + schedule_work(&fw_info->work); +} +EXPORT_SYMBOL(nxp_nci_fw_recv_frame); diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c new file mode 100644 index 000000000000..17bd67dbebf0 --- /dev/null +++ b/drivers/nfc/nxp-nci/i2c.c @@ -0,0 +1,415 @@ +/* + * I2C link layer for the NXP NCI driver + * + * Copyright (C) 2014 NXP Semiconductors All rights reserved. + * + * Authors: Clément Perrochaud <clement.perrochaud@nxp.com> + * + * Derived from PN544 device driver: + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/nfc.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> +#include <linux/platform_data/nxp-nci.h> +#include <linux/unaligned/access_ok.h> + +#include <net/nfc/nfc.h> + +#include "nxp-nci.h" + +#define NXP_NCI_I2C_DRIVER_NAME "nxp-nci_i2c" + +#define NXP_NCI_I2C_MAX_PAYLOAD 32 + +struct nxp_nci_i2c_phy { + struct i2c_client *i2c_dev; + struct nci_dev *ndev; + + unsigned int gpio_en; + unsigned int gpio_fw; + + int hard_fault; /* + * < 0 if hardware error occurred (e.g. i2c err) + * and prevents normal operation. + */ +}; + +static int nxp_nci_i2c_set_mode(void *phy_id, + enum nxp_nci_mode mode) +{ + struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id; + + gpio_set_value(phy->gpio_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0); + gpio_set_value(phy->gpio_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0); + usleep_range(10000, 15000); + + if (mode == NXP_NCI_MODE_COLD) + phy->hard_fault = 0; + + return 0; +} + +static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb) +{ + int r; + struct nxp_nci_i2c_phy *phy = phy_id; + struct i2c_client *client = phy->i2c_dev; + + if (phy->hard_fault != 0) + return phy->hard_fault; + + r = i2c_master_send(client, skb->data, skb->len); + if (r == -EREMOTEIO) { + /* Retry, chip was in standby */ + usleep_range(110000, 120000); + r = i2c_master_send(client, skb->data, skb->len); + } + + if (r < 0) { + nfc_err(&client->dev, "Error %d on I2C send\n", r); + } else if (r != skb->len) { + nfc_err(&client->dev, + "Invalid length sent: %u (expected %u)\n", + r, skb->len); + r = -EREMOTEIO; + } else { + /* Success but return 0 and not number of bytes */ + r = 0; + } + + return r; +} + +static struct nxp_nci_phy_ops i2c_phy_ops = { + .set_mode = nxp_nci_i2c_set_mode, + .write = nxp_nci_i2c_write, +}; + +static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy, + struct sk_buff **skb) +{ + struct i2c_client *client = phy->i2c_dev; + u16 header; + size_t frame_len; + int r; + + r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN); + if (r < 0) { + goto fw_read_exit; + } else if (r != NXP_NCI_FW_HDR_LEN) { + nfc_err(&client->dev, "Incorrect header length: %u\n", r); + r = -EBADMSG; + goto fw_read_exit; + } + + frame_len = (get_unaligned_be16(&header) & NXP_NCI_FW_FRAME_LEN_MASK) + + NXP_NCI_FW_CRC_LEN; + + *skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto fw_read_exit; + } + + memcpy(skb_put(*skb, NXP_NCI_FW_HDR_LEN), &header, NXP_NCI_FW_HDR_LEN); + + r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len); + if (r != frame_len) { + nfc_err(&client->dev, + "Invalid frame length: %u (expected %zu)\n", + r, frame_len); + r = -EBADMSG; + goto fw_read_exit_free_skb; + } + + return 0; + +fw_read_exit_free_skb: + kfree_skb(*skb); +fw_read_exit: + return r; +} + +static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy, + struct sk_buff **skb) +{ + struct nci_ctrl_hdr header; /* May actually be a data header */ + struct i2c_client *client = phy->i2c_dev; + int r; + + r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE); + if (r < 0) { + goto nci_read_exit; + } else if (r != NCI_CTRL_HDR_SIZE) { + nfc_err(&client->dev, "Incorrect header length: %u\n", r); + r = -EBADMSG; + goto nci_read_exit; + } + + *skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto nci_read_exit; + } + + memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), (void *) &header, + NCI_CTRL_HDR_SIZE); + + r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen); + if (r != header.plen) { + nfc_err(&client->dev, + "Invalid frame payload length: %u (expected %u)\n", + r, header.plen); + r = -EBADMSG; + goto nci_read_exit_free_skb; + } + + return 0; + +nci_read_exit_free_skb: + kfree_skb(*skb); +nci_read_exit: + return r; +} + +static irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id) +{ + struct nxp_nci_i2c_phy *phy = phy_id; + struct i2c_client *client; + struct nxp_nci_info *info; + + struct sk_buff *skb = NULL; + int r = 0; + + if (!phy || !phy->ndev) + goto exit_irq_none; + + client = phy->i2c_dev; + + if (!client || irq != client->irq) + goto exit_irq_none; + + info = nci_get_drvdata(phy->ndev); + + if (!info) + goto exit_irq_none; + + mutex_lock(&info->info_lock); + + if (phy->hard_fault != 0) + goto exit_irq_handled; + + switch (info->mode) { + case NXP_NCI_MODE_NCI: + r = nxp_nci_i2c_nci_read(phy, &skb); + break; + case NXP_NCI_MODE_FW: + r = nxp_nci_i2c_fw_read(phy, &skb); + break; + case NXP_NCI_MODE_COLD: + r = -EREMOTEIO; + break; + } + + if (r == -EREMOTEIO) { + phy->hard_fault = r; + skb = NULL; + } else if (r < 0) { + nfc_err(&client->dev, "Read failed with error %d\n", r); + goto exit_irq_handled; + } + + switch (info->mode) { + case NXP_NCI_MODE_NCI: + nci_recv_frame(phy->ndev, skb); + break; + case NXP_NCI_MODE_FW: + nxp_nci_fw_recv_frame(phy->ndev, skb); + break; + case NXP_NCI_MODE_COLD: + break; + } + +exit_irq_handled: + mutex_unlock(&info->info_lock); + return IRQ_HANDLED; +exit_irq_none: + WARN_ON_ONCE(1); + return IRQ_NONE; +} + +#ifdef CONFIG_OF + +static int nxp_nci_i2c_parse_devtree(struct i2c_client *client) +{ + struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client); + struct device_node *pp; + int r; + + pp = client->dev.of_node; + if (!pp) + return -ENODEV; + + r = of_get_named_gpio(pp, "enable-gpios", 0); + if (r == -EPROBE_DEFER) + r = of_get_named_gpio(pp, "enable-gpios", 0); + if (r < 0) { + nfc_err(&client->dev, "Failed to get EN gpio, error: %d\n", r); + return r; + } + phy->gpio_en = r; + + r = of_get_named_gpio(pp, "firmware-gpios", 0); + if (r == -EPROBE_DEFER) + r = of_get_named_gpio(pp, "firmware-gpios", 0); + if (r < 0) { + nfc_err(&client->dev, "Failed to get FW gpio, error: %d\n", r); + return r; + } + phy->gpio_fw = r; + + r = irq_of_parse_and_map(pp, 0); + if (r < 0) { + nfc_err(&client->dev, "Unable to get irq, error: %d\n", r); + return r; + } + client->irq = r; + + return 0; +} + +#else + +static int nxp_nci_i2c_parse_devtree(struct i2c_client *client) +{ + return -ENODEV; +} + +#endif + +static int nxp_nci_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct nxp_nci_i2c_phy *phy; + struct nxp_nci_nfc_platform_data *pdata; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); + r = -ENODEV; + goto probe_exit; + } + + phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy), + GFP_KERNEL); + if (!phy) { + r = -ENOMEM; + goto probe_exit; + } + + phy->i2c_dev = client; + i2c_set_clientdata(client, phy); + + pdata = client->dev.platform_data; + + if (!pdata && client->dev.of_node) { + r = nxp_nci_i2c_parse_devtree(client); + if (r < 0) { + nfc_err(&client->dev, "Failed to get DT data\n"); + goto probe_exit; + } + } else if (pdata) { + phy->gpio_en = pdata->gpio_en; + phy->gpio_fw = pdata->gpio_fw; + client->irq = pdata->irq; + } else { + nfc_err(&client->dev, "No platform data\n"); + r = -EINVAL; + goto probe_exit; + } + + r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en, + GPIOF_OUT_INIT_LOW, "nxp_nci_en"); + if (r < 0) + goto probe_exit; + + r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw, + GPIOF_OUT_INIT_LOW, "nxp_nci_fw"); + if (r < 0) + goto probe_exit; + + r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops, + NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev); + if (r < 0) + goto probe_exit; + + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); + +probe_exit: + return r; +} + +static int nxp_nci_i2c_remove(struct i2c_client *client) +{ + struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client); + + nxp_nci_remove(phy->ndev); + free_irq(client->irq, phy); + + return 0; +} + +static struct i2c_device_id nxp_nci_i2c_id_table[] = { + {"nxp-nci_i2c", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table); + +static const struct of_device_id of_nxp_nci_i2c_match[] = { + { .compatible = "nxp,nxp-nci-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match); + +static struct i2c_driver nxp_nci_i2c_driver = { + .driver = { + .name = NXP_NCI_I2C_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_nxp_nci_i2c_match), + }, + .probe = nxp_nci_i2c_probe, + .id_table = nxp_nci_i2c_id_table, + .remove = nxp_nci_i2c_remove, +}; + +module_i2c_driver(nxp_nci_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers"); +MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>"); diff --git a/drivers/nfc/nxp-nci/nxp-nci.h b/drivers/nfc/nxp-nci/nxp-nci.h new file mode 100644 index 000000000000..f1fecc4e2457 --- /dev/null +++ b/drivers/nfc/nxp-nci/nxp-nci.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 NXP Semiconductors All rights reserved. + * + * Authors: Clément Perrochaud <clement.perrochaud@nxp.com> + * + * Derived from PN544 device driver: + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __LOCAL_NXP_NCI_H_ +#define __LOCAL_NXP_NCI_H_ + +#include <linux/completion.h> +#include <linux/firmware.h> +#include <linux/nfc.h> +#include <linux/platform_data/nxp-nci.h> + +#include <net/nfc/nci_core.h> + +#define NXP_NCI_FW_HDR_LEN 2 +#define NXP_NCI_FW_CRC_LEN 2 + +#define NXP_NCI_FW_FRAME_LEN_MASK 0x03FF + +enum nxp_nci_mode { + NXP_NCI_MODE_COLD, + NXP_NCI_MODE_NCI, + NXP_NCI_MODE_FW +}; + +struct nxp_nci_phy_ops { + int (*set_mode)(void *id, enum nxp_nci_mode mode); + int (*write)(void *id, struct sk_buff *skb); +}; + +struct nxp_nci_fw_info { + char name[NFC_FIRMWARE_NAME_MAXSIZE + 1]; + const struct firmware *fw; + + size_t size; + size_t written; + + const u8 *data; + size_t frame_size; + + struct work_struct work; + struct completion cmd_completion; + + int cmd_result; +}; + +struct nxp_nci_info { + struct nci_dev *ndev; + void *phy_id; + struct device *pdev; + + enum nxp_nci_mode mode; + + struct nxp_nci_phy_ops *phy_ops; + unsigned int max_payload; + + struct mutex info_lock; + + struct nxp_nci_fw_info fw_info; +}; + +int nxp_nci_fw_download(struct nci_dev *ndev, const char *firmware_name); +void nxp_nci_fw_work(struct work_struct *work); +void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb); +void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result); + +int nxp_nci_probe(void *phy_id, struct device *pdev, + struct nxp_nci_phy_ops *phy_ops, unsigned int max_payload, + struct nci_dev **ndev); +void nxp_nci_remove(struct nci_dev *ndev); + +#endif /* __LOCAL_NXP_NCI_H_ */ diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index d46a700a9637..a03e4eb5fe29 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1820,7 +1820,7 @@ static int pn533_rf_complete(struct pn533 *dev, void *arg, if (IS_ERR(resp)) { rc = PTR_ERR(resp); - nfc_err(&dev->interface->dev, "RF setting error %d", rc); + nfc_err(&dev->interface->dev, "RF setting error %d\n", rc); return rc; } @@ -2554,8 +2554,10 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, } skb = pn533_build_response(dev); - if (!skb) + if (!skb) { + rc = -ENOMEM; goto error; + } arg->cb(arg->cb_context, skb, 0); kfree(arg); diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index cdde745b96bd..6fd986f5ac3e 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -953,7 +953,7 @@ static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client) } nfc_info(dev, "GPIO resource, no:%d irq:%d\n", - desc_to_gpio(gpiod_irq), ret); + desc_to_gpio(gpiod_irq), ret); client->irq = ret; return 0; @@ -1062,11 +1062,8 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy), GFP_KERNEL); - if (!phy) { - nfc_err(&client->dev, - "Cannot allocate memory for pn544 i2c phy.\n"); + if (!phy) return -ENOMEM; - } INIT_WORK(&phy->fw_work, pn544_hci_i2c_fw_work); phy->fw_work_state = FW_WORK_STATE_IDLE; diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c index 4ac4d31f6c59..87d509996704 100644 --- a/drivers/nfc/port100.c +++ b/drivers/nfc/port100.c @@ -604,11 +604,11 @@ static void port100_recv_response(struct urb *urb) case -ECONNRESET: case -ENOENT: nfc_err(&dev->interface->dev, - "The urb has been canceled (status %d)", urb->status); + "The urb has been canceled (status %d)\n", urb->status); goto sched_wq; case -ESHUTDOWN: default: - nfc_err(&dev->interface->dev, "Urb failure (status %d)", + nfc_err(&dev->interface->dev, "Urb failure (status %d)\n", urb->status); goto sched_wq; } @@ -616,7 +616,7 @@ static void port100_recv_response(struct urb *urb) in_frame = dev->in_urb->transfer_buffer; if (!port100_rx_frame_is_valid(in_frame)) { - nfc_err(&dev->interface->dev, "Received an invalid frame"); + nfc_err(&dev->interface->dev, "Received an invalid frame\n"); cmd->status = -EIO; goto sched_wq; } @@ -626,7 +626,7 @@ static void port100_recv_response(struct urb *urb) if (!port100_rx_frame_is_cmd_response(dev, in_frame)) { nfc_err(&dev->interface->dev, - "It's not the response to the last command"); + "It's not the response to the last command\n"); cmd->status = -EIO; goto sched_wq; } @@ -657,11 +657,11 @@ static void port100_recv_ack(struct urb *urb) case -ECONNRESET: case -ENOENT: nfc_err(&dev->interface->dev, - "The urb has been stopped (status %d)", urb->status); + "The urb has been stopped (status %d)\n", urb->status); goto sched_wq; case -ESHUTDOWN: default: - nfc_err(&dev->interface->dev, "Urb failure (status %d)", + nfc_err(&dev->interface->dev, "Urb failure (status %d)\n", urb->status); goto sched_wq; } @@ -669,7 +669,7 @@ static void port100_recv_ack(struct urb *urb) in_frame = dev->in_urb->transfer_buffer; if (!port100_rx_frame_is_ack(in_frame)) { - nfc_err(&dev->interface->dev, "Received an invalid ack"); + nfc_err(&dev->interface->dev, "Received an invalid ack\n"); cmd->status = -EIO; goto sched_wq; } @@ -677,7 +677,7 @@ static void port100_recv_ack(struct urb *urb) rc = port100_submit_urb_for_response(dev, GFP_ATOMIC); if (rc) { nfc_err(&dev->interface->dev, - "usb_submit_urb failed with result %d", rc); + "usb_submit_urb failed with result %d\n", rc); cmd->status = rc; goto sched_wq; } @@ -873,11 +873,11 @@ static void port100_send_complete(struct urb *urb) case -ECONNRESET: case -ENOENT: nfc_err(&dev->interface->dev, - "The urb has been stopped (status %d)", urb->status); + "The urb has been stopped (status %d)\n", urb->status); break; case -ESHUTDOWN: default: - nfc_err(&dev->interface->dev, "Urb failure (status %d)", + nfc_err(&dev->interface->dev, "Urb failure (status %d)\n", urb->status); } } @@ -1094,7 +1094,7 @@ static void port100_in_comm_rf_complete(struct port100 *dev, void *arg, if (resp->len < 4) { nfc_err(&dev->interface->dev, - "Invalid packet length received.\n"); + "Invalid packet length received\n"); rc = -EIO; goto error; } @@ -1250,7 +1250,7 @@ static bool port100_tg_target_activated(struct port100 *dev, u8 tgt_activated) PORT100_MDAA_TGT_WAS_ACTIVATED_MASK; break; default: - nfc_err(&dev->interface->dev, "Unknonwn command type.\n"); + nfc_err(&dev->interface->dev, "Unknown command type\n"); return false; } @@ -1481,7 +1481,7 @@ static int port100_probe(struct usb_interface *interface, cmd_type_mask = port100_get_command_type_mask(dev); if (!cmd_type_mask) { nfc_err(&interface->dev, - "Could not get supported command types.\n"); + "Could not get supported command types\n"); rc = -ENODEV; goto error; } @@ -1494,7 +1494,7 @@ static int port100_probe(struct usb_interface *interface, rc = port100_set_command_type(dev, dev->cmd_type); if (rc) { nfc_err(&interface->dev, - "The device does not support command type %u.\n", + "The device does not support command type %u\n", dev->cmd_type); goto error; } @@ -1502,7 +1502,7 @@ static int port100_probe(struct usb_interface *interface, fw_version = port100_get_firmware_version(dev); if (!fw_version) nfc_err(&interface->dev, - "Could not get device firmware version.\n"); + "Could not get device firmware version\n"); nfc_info(&interface->dev, "Sony NFC Port-100 Series attached (firmware v%x.%02x)\n", @@ -1515,7 +1515,7 @@ static int port100_probe(struct usb_interface *interface, dev->skb_tailroom); if (!dev->nfc_digital_dev) { nfc_err(&interface->dev, - "Could not allocate nfc_digital_dev.\n"); + "Could not allocate nfc_digital_dev\n"); rc = -ENOMEM; goto error; } @@ -1526,7 +1526,7 @@ static int port100_probe(struct usb_interface *interface, rc = nfc_digital_register_device(dev->nfc_digital_dev); if (rc) { nfc_err(&interface->dev, - "Could not register digital device.\n"); + "Could not register digital device\n"); goto free_nfc_dev; } @@ -1562,7 +1562,7 @@ static void port100_disconnect(struct usb_interface *interface) kfree(dev->cmd); - nfc_info(&interface->dev, "Sony Port-100 NFC device disconnected"); + nfc_info(&interface->dev, "Sony Port-100 NFC device disconnected\n"); } static struct usb_driver port100_driver = { diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c index 24d3d240d5f4..d251f7229c4e 100644 --- a/drivers/nfc/st21nfca/st21nfca.c +++ b/drivers/nfc/st21nfca/st21nfca.c @@ -572,7 +572,7 @@ exit: return r; } -static int st21nfca_get_iso14443_3_uid(struct nfc_hci_dev *hdev, u8 *gate, +static int st21nfca_get_iso14443_3_uid(struct nfc_hci_dev *hdev, u8 *uid, int *len) { int r; @@ -588,7 +588,7 @@ static int st21nfca_get_iso14443_3_uid(struct nfc_hci_dev *hdev, u8 *gate, goto exit; } - gate = uid_skb->data; + memcpy(uid, uid_skb->data, uid_skb->len); *len = uid_skb->len; exit: kfree_skb(uid_skb); diff --git a/drivers/nfc/st21nfca/st21nfca_se.c b/drivers/nfc/st21nfca/st21nfca_se.c index bd13cac9c66a..3197e9bb66f7 100644 --- a/drivers/nfc/st21nfca/st21nfca_se.c +++ b/drivers/nfc/st21nfca/st21nfca_se.c @@ -310,6 +310,13 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, case ST21NFCA_EVT_CONNECTIVITY: break; case ST21NFCA_EVT_TRANSACTION: + /* + * According to specification etsi 102 622 + * 11.2.2.4 EVT_TRANSACTION Table 52 + * Description Tag Length + * AID 81 5 to 16 + * PARAMETERS 82 0 to 255 + */ if (skb->len < NFC_MIN_AID_LENGTH + 2 && skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) return -EPROTO; @@ -318,8 +325,10 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, skb->len - 2, GFP_KERNEL); transaction->aid_len = skb->data[1]; - memcpy(transaction->aid, &skb->data[2], skb->data[1]); + memcpy(transaction->aid, &skb->data[2], + transaction->aid_len); + /* Check next byte is PARAMETERS tag (82) */ if (skb->data[transaction->aid_len + 2] != NFC_EVT_TRANSACTION_PARAMS_TAG) return -EPROTO; diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c index eb886932d972..76a4cad41cec 100644 --- a/drivers/nfc/st21nfcb/i2c.c +++ b/drivers/nfc/st21nfcb/i2c.c @@ -109,7 +109,7 @@ static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb) return phy->ndlc->hard_fault; r = i2c_master_send(client, skb->data, skb->len); - if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + if (r < 0) { /* Retry, chip was in standby */ usleep_range(1000, 4000); r = i2c_master_send(client, skb->data, skb->len); } @@ -148,7 +148,7 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy, struct i2c_client *client = phy->i2c_dev; r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE); - if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + if (r < 0) { /* Retry, chip was in standby */ usleep_range(1000, 4000); r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE); } @@ -313,11 +313,8 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client, phy = devm_kzalloc(&client->dev, sizeof(struct st21nfcb_i2c_phy), GFP_KERNEL); - if (!phy) { - nfc_err(&client->dev, - "Cannot allocate memory for st21nfcb i2c phy.\n"); + if (!phy) return -ENOMEM; - } phy->i2c_dev = client; diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c index 5fbf59d2138c..6014b5859465 100644 --- a/drivers/nfc/st21nfcb/ndlc.c +++ b/drivers/nfc/st21nfcb/ndlc.c @@ -256,10 +256,9 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, struct llt_ndlc *ndlc; ndlc = devm_kzalloc(dev, sizeof(struct llt_ndlc), GFP_KERNEL); - if (!ndlc) { - nfc_err(dev, "Cannot allocate memory for ndlc.\n"); + if (!ndlc) return -ENOMEM; - } + ndlc->ops = phy_ops; ndlc->phy_id = phy_id; ndlc->dev = dev; diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.c b/drivers/nfc/st21nfcb/st21nfcb_se.c index 7c82e9d87a65..24862a525fb5 100644 --- a/drivers/nfc/st21nfcb/st21nfcb_se.c +++ b/drivers/nfc/st21nfcb/st21nfcb_se.c @@ -321,6 +321,12 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev, break; case ST21NFCB_EVT_TRANSACTION: + /* According to specification etsi 102 622 + * 11.2.2.4 EVT_TRANSACTION Table 52 + * Description Tag Length + * AID 81 5 to 16 + * PARAMETERS 82 0 to 255 + */ if (skb->len < NFC_MIN_AID_LENGTH + 2 && skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) return -EPROTO; @@ -329,8 +335,9 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev, skb->len - 2, GFP_KERNEL); transaction->aid_len = skb->data[1]; - memcpy(transaction->aid, &skb->data[2], skb->data[1]); + memcpy(transaction->aid, &skb->data[2], transaction->aid_len); + /* Check next byte is PARAMETERS tag (82) */ if (skb->data[transaction->aid_len + 2] != NFC_EVT_TRANSACTION_PARAMS_TAG) return -EPROTO; @@ -340,6 +347,7 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev, transaction->aid_len + 4, transaction->params_len); r = nfc_se_transaction(ndev->nfc_dev, host, transaction); + break; default: return 1; } @@ -542,14 +550,12 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev) r = nci_hci_dev_session_init(ndev); if (r != NCI_HCI_ANY_OK) - goto exit; + goto free_dest_params; r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id, NCI_NFCEE_ENABLE); if (r != NCI_STATUS_OK) - goto exit; - - return 0; + goto free_dest_params; free_dest_params: kfree(dest_params); diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index d75b72ba2672..15a7ee3859dd 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -357,6 +357,15 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA); + /* + * Accessing PCI config without a proper delay after devices reset (not + * GPIO reset) was causing reboots on WRT300N v1.0. + * Tested delay 850 us lowered reboot chance to 50-80%, 1000 us fixed it + * completely. Flushing all writes was also tested but with no luck. + */ + if (pc->dev->bus->chip_id == 0x4704) + usleep_range(1000, 2000); + /* Enable PCI bridge BAR0 prefetch and burst */ val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); |