diff options
Diffstat (limited to 'drivers/net')
221 files changed, 3804 insertions, 1795 deletions
| diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 56b560558884..b7f1a9919033 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -214,6 +214,8 @@ static void bond_uninit(struct net_device *bond_dev);  static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,  						struct rtnl_link_stats64 *stats);  static void bond_slave_arr_handler(struct work_struct *work); +static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act, +				  int mod);  /*---------------------------- General routines -----------------------------*/ @@ -2127,6 +2129,7 @@ static void bond_miimon_commit(struct bonding *bond)  			continue;  		case BOND_LINK_UP: +			bond_update_speed_duplex(slave);  			bond_set_slave_link_state(slave, BOND_LINK_UP,  						  BOND_SLAVE_NOTIFY_NOW);  			slave->last_link_up = jiffies; @@ -2459,7 +2462,7 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,  		 struct slave *slave)  {  	struct arphdr *arp = (struct arphdr *)skb->data; -	struct slave *curr_active_slave; +	struct slave *curr_active_slave, *curr_arp_slave;  	unsigned char *arp_ptr;  	__be32 sip, tip;  	int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP); @@ -2506,26 +2509,41 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,  		     &sip, &tip);  	curr_active_slave = rcu_dereference(bond->curr_active_slave); +	curr_arp_slave = rcu_dereference(bond->current_arp_slave); -	/* Backup slaves won't see the ARP reply, but do come through -	 * here for each ARP probe (so we swap the sip/tip to validate -	 * the probe).  In a "redundant switch, common router" type of -	 * configuration, the ARP probe will (hopefully) travel from -	 * the active, through one switch, the router, then the other -	 * switch before reaching the backup. +	/* We 'trust' the received ARP enough to validate it if: +	 * +	 * (a) the slave receiving the ARP is active (which includes the +	 * current ARP slave, if any), or +	 * +	 * (b) the receiving slave isn't active, but there is a currently +	 * active slave and it received valid arp reply(s) after it became +	 * the currently active slave, or +	 * +	 * (c) there is an ARP slave that sent an ARP during the prior ARP +	 * interval, and we receive an ARP reply on any slave.  We accept +	 * these because switch FDB update delays may deliver the ARP +	 * reply to a slave other than the sender of the ARP request.  	 * -	 * We 'trust' the arp requests if there is an active slave and -	 * it received valid arp reply(s) after it became active. This -	 * is done to avoid endless looping when we can't reach the +	 * Note: for (b), backup slaves are receiving the broadcast ARP +	 * request, not a reply.  This request passes from the sending +	 * slave through the L2 switch(es) to the receiving slave.  Since +	 * this is checking the request, sip/tip are swapped for +	 * validation. +	 * +	 * This is done to avoid endless looping when we can't reach the  	 * arp_ip_target and fool ourselves with our own arp requests.  	 */ -  	if (bond_is_active_slave(slave))  		bond_validate_arp(bond, slave, sip, tip);  	else if (curr_active_slave &&  		 time_after(slave_last_rx(bond, curr_active_slave),  			    curr_active_slave->last_link_up))  		bond_validate_arp(bond, slave, tip, sip); +	else if (curr_arp_slave && (arp->ar_op == htons(ARPOP_REPLY)) && +		 bond_time_in_interval(bond, +				       dev_trans_start(curr_arp_slave->dev), 1)) +		bond_validate_arp(bond, slave, sip, tip);  out_unlock:  	if (arp != (struct arphdr *)skb->data) diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 575790e8a75a..74a7dfecee27 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -843,7 +843,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)  		if (clear_intf)  			mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00); -		if (eflag) +		if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR))  			mcp251x_write_bits(spi, EFLG, eflag, 0x00);  		/* Update can state */ diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index fc5b75675cd8..eb7192fab593 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -117,6 +117,9 @@ MODULE_LICENSE("GPL v2");   */  #define EMS_USB_ARM7_CLOCK 8000000 +#define CPC_TX_QUEUE_TRIGGER_LOW	25 +#define CPC_TX_QUEUE_TRIGGER_HIGH	35 +  /*   * CAN-Message representation in a CPC_MSG. Message object type is   * CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or @@ -278,6 +281,11 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)  	switch (urb->status) {  	case 0:  		dev->free_slots = dev->intr_in_buffer[1]; +		if(dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH){ +			if (netif_queue_stopped(netdev)){ +				netif_wake_queue(netdev); +			} +		}  		break;  	case -ECONNRESET: /* unlink */ @@ -526,8 +534,6 @@ static void ems_usb_write_bulk_callback(struct urb *urb)  	/* Release context */  	context->echo_index = MAX_TX_URBS; -	if (netif_queue_stopped(netdev)) -		netif_wake_queue(netdev);  }  /* @@ -587,7 +593,7 @@ static int ems_usb_start(struct ems_usb *dev)  	int err, i;  	dev->intr_in_buffer[0] = 0; -	dev->free_slots = 15; /* initial size */ +	dev->free_slots = 50; /* initial size */  	for (i = 0; i < MAX_RX_URBS; i++) {  		struct urb *urb = NULL; @@ -835,7 +841,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne  		/* Slow down tx path */  		if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS || -		    dev->free_slots < 5) { +		    dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) {  			netif_stop_queue(netdev);  		}  	} diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 5eee62badf45..cbc99d5649af 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -826,9 +826,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface  static void gs_destroy_candev(struct gs_can *dev)  {  	unregister_candev(dev->netdev); -	free_candev(dev->netdev);  	usb_kill_anchored_urbs(&dev->tx_submitted); -	kfree(dev); +	free_candev(dev->netdev);  }  static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -913,12 +912,15 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *  	for (i = 0; i < icount; i++) {  		dev->canch[i] = gs_make_candev(i, intf);  		if (IS_ERR_OR_NULL(dev->canch[i])) { +			/* save error code to return later */ +			rc = PTR_ERR(dev->canch[i]); +  			/* on failure destroy previously created candevs */  			icount = i; -			for (i = 0; i < icount; i++) { +			for (i = 0; i < icount; i++)  				gs_destroy_candev(dev->canch[i]); -				dev->canch[i] = NULL; -			} + +			usb_kill_anchored_urbs(&dev->rx_submitted);  			kfree(dev);  			return rc;  		} @@ -939,16 +941,12 @@ static void gs_usb_disconnect(struct usb_interface *intf)  		return;  	} -	for (i = 0; i < GS_MAX_INTF; i++) { -		struct gs_can *can = dev->canch[i]; - -		if (!can) -			continue; - -		gs_destroy_candev(can); -	} +	for (i = 0; i < GS_MAX_INTF; i++) +		if (dev->canch[i]) +			gs_destroy_candev(dev->canch[i]);  	usb_kill_anchored_urbs(&dev->rx_submitted); +	kfree(dev);  }  static const struct usb_device_id gs_usb_table[] = { diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index cc6c54553418..a47f52f44b0d 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -25,6 +25,7 @@  static const struct mv88e6xxx_switch_id mv88e6352_table[] = {  	{ PORT_SWITCH_ID_6172, "Marvell 88E6172" },  	{ PORT_SWITCH_ID_6176, "Marvell 88E6176" }, +	{ PORT_SWITCH_ID_6240, "Marvell 88E6240" },  	{ PORT_SWITCH_ID_6320, "Marvell 88E6320" },  	{ PORT_SWITCH_ID_6320_A1, "Marvell 88E6320 (A1)" },  	{ PORT_SWITCH_ID_6320_A2, "Marvell 88e6320 (A2)" }, diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 9fe33fc3c2b9..512c8c0be1b4 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1532,7 +1532,7 @@ int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,  	/* no PVID with ranges, otherwise it's a bug */  	if (pvid) -		err = _mv88e6xxx_port_pvid_set(ds, port, vid); +		err = _mv88e6xxx_port_pvid_set(ds, port, vlan->vid_end);  unlock:  	mutex_unlock(&ps->smi_mutex); @@ -1555,7 +1555,7 @@ static int _mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)  	if (vlan.vid != vid || !vlan.valid ||  	    vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) -		return -ENOENT; +		return -EOPNOTSUPP;  	vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; @@ -1582,6 +1582,7 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,  			    const struct switchdev_obj_port_vlan *vlan)  {  	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); +	const u16 defpvid = 4000 + ds->index * DSA_MAX_PORTS + port;  	u16 pvid, vid;  	int err = 0; @@ -1597,7 +1598,8 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,  			goto unlock;  		if (vid == pvid) { -			err = _mv88e6xxx_port_pvid_set(ds, port, 0); +			/* restore reserved VLAN ID */ +			err = _mv88e6xxx_port_pvid_set(ds, port, defpvid);  			if (err)  				goto unlock;  		} @@ -1889,26 +1891,20 @@ unlock:  int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members)  { -	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); -	const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port; -	int err; - -	/* The port joined a bridge, so leave its reserved VLAN */ -	mutex_lock(&ps->smi_mutex); -	err = _mv88e6xxx_port_vlan_del(ds, port, pvid); -	if (!err) -		err = _mv88e6xxx_port_pvid_set(ds, port, 0); -	mutex_unlock(&ps->smi_mutex); -	return err; +	return 0;  }  int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members)  { +	return 0; +} + +static int mv88e6xxx_setup_port_default_vlan(struct dsa_switch *ds, int port) +{  	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);  	const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;  	int err; -	/* The port left the bridge, so join its reserved VLAN */  	mutex_lock(&ps->smi_mutex);  	err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true);  	if (!err) @@ -2163,7 +2159,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)  	 * database, and allow every port to egress frames on all other ports.  	 */  	reg = BIT(ps->num_ports) - 1; /* all ports */ -	ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg & ~port); +	reg &= ~BIT(port); /* except itself */ +	ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg);  	if (ret)  		goto abort; @@ -2191,8 +2188,7 @@ int mv88e6xxx_setup_ports(struct dsa_switch *ds)  		if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))  			continue; -		/* setup the unbridged state */ -		ret = mv88e6xxx_port_bridge_leave(ds, i, 0); +		ret = mv88e6xxx_setup_port_default_vlan(ds, i);  		if (ret < 0)  			return ret;  	} diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 79e1a0282163..17b2126075e0 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -2461,7 +2461,7 @@ boomerang_interrupt(int irq, void *dev_id)  					int i;  					pci_unmap_single(VORTEX_PCI(vp),  							le32_to_cpu(vp->tx_ring[entry].frag[0].addr), -							le32_to_cpu(vp->tx_ring[entry].frag[0].length), +							le32_to_cpu(vp->tx_ring[entry].frag[0].length)&0xFFF,  							PCI_DMA_TODEVICE);  					for (i=1; i<=skb_shinfo(skb)->nr_frags; i++) diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c index 2777289a26c0..2f79d29f17f2 100644 --- a/drivers/net/ethernet/8390/pcnet_cs.c +++ b/drivers/net/ethernet/8390/pcnet_cs.c @@ -1501,6 +1501,7 @@ static const struct pcmcia_device_id pcnet_ids[] = {  	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),  	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),  	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121), +	PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0009),  	PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),  	PCMCIA_DEVICE_PROD_ID1234("Socket", "CF 10/100 Ethernet Card", "Revision B", "05/11/06", 0xb38bcc2e, 0x4de88352, 0xeaca6c8d, 0x7e57c22e),  	PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b), diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index 3f3bcbea15bd..0907ab6ff309 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -2380,7 +2380,7 @@ static int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter)  						    sizeof(u32),  						    &tx_ring->tx_status_pa,  						    GFP_KERNEL); -	if (!tx_ring->tx_status_pa) { +	if (!tx_ring->tx_status) {  		dev_err(&adapter->pdev->dev,  			"Cannot alloc memory for Tx status block\n");  		return -ENOMEM; diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 17472851674f..f749e4d389eb 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -193,7 +193,6 @@ static void altera_tse_mdio_destroy(struct net_device *dev)  			    priv->mdio->id);  	mdiobus_unregister(priv->mdio); -	kfree(priv->mdio->irq);  	mdiobus_free(priv->mdio);  	priv->mdio = NULL;  } diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c index 87e727b921dc..fcdf5dda448f 100644 --- a/drivers/net/ethernet/amd/am79c961a.c +++ b/drivers/net/ethernet/amd/am79c961a.c @@ -50,8 +50,8 @@ static const char version[] =  static void write_rreg(u_long base, u_int reg, u_int val)  {  	asm volatile( -	"str%?h	%1, [%2]	@ NET_RAP\n\t" -	"str%?h	%0, [%2, #-4]	@ NET_RDP" +	"strh	%1, [%2]	@ NET_RAP\n\t" +	"strh	%0, [%2, #-4]	@ NET_RDP"  	:  	: "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));  } @@ -60,8 +60,8 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg)  {  	unsigned short v;  	asm volatile( -	"str%?h	%1, [%2]	@ NET_RAP\n\t" -	"ldr%?h	%0, [%2, #-4]	@ NET_RDP" +	"strh	%1, [%2]	@ NET_RAP\n\t" +	"ldrh	%0, [%2, #-4]	@ NET_RDP"  	: "=r" (v)  	: "r" (reg), "r" (ISAIO_BASE + 0x0464));  	return v; @@ -70,8 +70,8 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg)  static inline void write_ireg(u_long base, u_int reg, u_int val)  {  	asm volatile( -	"str%?h	%1, [%2]	@ NET_RAP\n\t" -	"str%?h	%0, [%2, #8]	@ NET_IDP" +	"strh	%1, [%2]	@ NET_RAP\n\t" +	"strh	%0, [%2, #8]	@ NET_IDP"  	:  	: "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));  } @@ -80,8 +80,8 @@ static inline unsigned short read_ireg(u_long base_addr, u_int reg)  {  	u_short v;  	asm volatile( -	"str%?h	%1, [%2]	@ NAT_RAP\n\t" -	"ldr%?h	%0, [%2, #8]	@ NET_IDP\n\t" +	"strh	%1, [%2]	@ NAT_RAP\n\t" +	"ldrh	%0, [%2, #8]	@ NET_IDP\n\t"  	: "=r" (v)  	: "r" (reg), "r" (ISAIO_BASE + 0x0464));  	return v; @@ -96,7 +96,7 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne  	offset = ISAMEM_BASE + (offset << 1);  	length = (length + 1) & ~1;  	if ((int)buf & 2) { -		asm volatile("str%?h	%2, [%0], #4" +		asm volatile("strh	%2, [%0], #4"  		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));  		buf += 2;  		length -= 2; @@ -104,20 +104,20 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne  	while (length > 8) {  		register unsigned int tmp asm("r2"), tmp2 asm("r3");  		asm volatile( -			"ldm%?ia	%0!, {%1, %2}" +			"ldmia	%0!, {%1, %2}"  			: "+r" (buf), "=&r" (tmp), "=&r" (tmp2));  		length -= 8;  		asm volatile( -			"str%?h	%1, [%0], #4\n\t" -			"mov%?	%1, %1, lsr #16\n\t" -			"str%?h	%1, [%0], #4\n\t" -			"str%?h	%2, [%0], #4\n\t" -			"mov%?	%2, %2, lsr #16\n\t" -			"str%?h	%2, [%0], #4" +			"strh	%1, [%0], #4\n\t" +			"mov	%1, %1, lsr #16\n\t" +			"strh	%1, [%0], #4\n\t" +			"strh	%2, [%0], #4\n\t" +			"mov	%2, %2, lsr #16\n\t" +			"strh	%2, [%0], #4"  		: "+r" (offset), "=&r" (tmp), "=&r" (tmp2));  	}  	while (length > 0) { -		asm volatile("str%?h	%2, [%0], #4" +		asm volatile("strh	%2, [%0], #4"  		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));  		buf += 2;  		length -= 2; @@ -132,23 +132,23 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned  	if ((int)buf & 2) {  		unsigned int tmp;  		asm volatile( -			"ldr%?h	%2, [%0], #4\n\t" -			"str%?b	%2, [%1], #1\n\t" -			"mov%?	%2, %2, lsr #8\n\t" -			"str%?b	%2, [%1], #1" +			"ldrh	%2, [%0], #4\n\t" +			"strb	%2, [%1], #1\n\t" +			"mov	%2, %2, lsr #8\n\t" +			"strb	%2, [%1], #1"  		: "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));  		length -= 2;  	}  	while (length > 8) {  		register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3;  		asm volatile( -			"ldr%?h	%2, [%0], #4\n\t" -			"ldr%?h	%4, [%0], #4\n\t" -			"ldr%?h	%3, [%0], #4\n\t" -			"orr%?	%2, %2, %4, lsl #16\n\t" -			"ldr%?h	%4, [%0], #4\n\t" -			"orr%?	%3, %3, %4, lsl #16\n\t" -			"stm%?ia	%1!, {%2, %3}" +			"ldrh	%2, [%0], #4\n\t" +			"ldrh	%4, [%0], #4\n\t" +			"ldrh	%3, [%0], #4\n\t" +			"orr	%2, %2, %4, lsl #16\n\t" +			"ldrh	%4, [%0], #4\n\t" +			"orr	%3, %3, %4, lsl #16\n\t" +			"stmia	%1!, {%2, %3}"  		: "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)  		: "0" (offset), "1" (buf));  		length -= 8; @@ -156,10 +156,10 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned  	while (length > 0) {  		unsigned int tmp;  		asm volatile( -			"ldr%?h	%2, [%0], #4\n\t" -			"str%?b	%2, [%1], #1\n\t" -			"mov%?	%2, %2, lsr #8\n\t" -			"str%?b	%2, [%1], #1" +			"ldrh	%2, [%0], #4\n\t" +			"strb	%2, [%1], #1\n\t" +			"mov	%2, %2, lsr #8\n\t" +			"strb	%2, [%1], #1"  		: "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));  		length -= 2;  	} diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c index 256f590f6bb1..3a7ebfdda57d 100644 --- a/drivers/net/ethernet/amd/lance.c +++ b/drivers/net/ethernet/amd/lance.c @@ -547,8 +547,8 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int  	/* Make certain the data structures used by the LANCE are aligned and DMAble. */  	lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL); -	if(lp==NULL) -		return -ENODEV; +	if (!lp) +		return -ENOMEM;  	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);  	dev->ml_priv = lp;  	lp->name = chipname; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index a4799c1fc7d4..5eb9b20c0eea 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -628,6 +628,7 @@ static int xgene_enet_register_irq(struct net_device *ndev)  	int ret;  	ring = pdata->rx_ring; +	irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);  	ret = devm_request_irq(dev, ring->irq, xgene_enet_rx_irq,  			       IRQF_SHARED, ring->irq_name, ring);  	if (ret) @@ -635,6 +636,7 @@ static int xgene_enet_register_irq(struct net_device *ndev)  	if (pdata->cq_cnt) {  		ring = pdata->tx_ring->cp_ring; +		irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);  		ret = devm_request_irq(dev, ring->irq, xgene_enet_rx_irq,  				       IRQF_SHARED, ring->irq_name, ring);  		if (ret) { @@ -649,15 +651,19 @@ static int xgene_enet_register_irq(struct net_device *ndev)  static void xgene_enet_free_irq(struct net_device *ndev)  {  	struct xgene_enet_pdata *pdata; +	struct xgene_enet_desc_ring *ring;  	struct device *dev;  	pdata = netdev_priv(ndev);  	dev = ndev_to_dev(ndev); -	devm_free_irq(dev, pdata->rx_ring->irq, pdata->rx_ring); +	ring = pdata->rx_ring; +	irq_clear_status_flags(ring->irq, IRQ_DISABLE_UNLAZY); +	devm_free_irq(dev, ring->irq, ring);  	if (pdata->cq_cnt) { -		devm_free_irq(dev, pdata->tx_ring->cp_ring->irq, -			      pdata->tx_ring->cp_ring); +		ring = pdata->tx_ring->cp_ring; +		irq_clear_status_flags(ring->irq, IRQ_DISABLE_UNLAZY); +		devm_free_irq(dev, ring->irq, ring);  	}  } diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 70d5b62c125a..248dfc40a761 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -25,6 +25,7 @@  #include <linux/acpi.h>  #include <linux/clk.h>  #include <linux/efi.h> +#include <linux/irq.h>  #include <linux/io.h>  #include <linux/of_platform.h>  #include <linux/of_net.h> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index abe1eabc0171..6446af1403f7 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -163,7 +163,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)  		struct sk_buff *skb = tx_buff->skb;  		unsigned int info = le32_to_cpu(txbd->info); -		if ((info & FOR_EMAC) || !txbd->data) +		if ((info & FOR_EMAC) || !txbd->data || !skb)  			break;  		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) { @@ -191,6 +191,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)  		txbd->data = 0;  		txbd->info = 0; +		tx_buff->skb = NULL;  		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;  	} @@ -446,6 +447,9 @@ static int arc_emac_open(struct net_device *ndev)  		*last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM;  	} +	priv->txbd_curr = 0; +	priv->txbd_dirty = 0; +  	/* Clean Tx BD's */  	memset(priv->txbd, 0, TX_RING_SZ); @@ -514,6 +518,64 @@ static void arc_emac_set_rx_mode(struct net_device *ndev)  }  /** + * arc_free_tx_queue - free skb from tx queue + * @ndev:	Pointer to the network device. + * + * This function must be called while EMAC disable + */ +static void arc_free_tx_queue(struct net_device *ndev) +{ +	struct arc_emac_priv *priv = netdev_priv(ndev); +	unsigned int i; + +	for (i = 0; i < TX_BD_NUM; i++) { +		struct arc_emac_bd *txbd = &priv->txbd[i]; +		struct buffer_state *tx_buff = &priv->tx_buff[i]; + +		if (tx_buff->skb) { +			dma_unmap_single(&ndev->dev, dma_unmap_addr(tx_buff, addr), +					 dma_unmap_len(tx_buff, len), DMA_TO_DEVICE); + +			/* return the sk_buff to system */ +			dev_kfree_skb_irq(tx_buff->skb); +		} + +		txbd->info = 0; +		txbd->data = 0; +		tx_buff->skb = NULL; +	} +} + +/** + * arc_free_rx_queue - free skb from rx queue + * @ndev:	Pointer to the network device. + * + * This function must be called while EMAC disable + */ +static void arc_free_rx_queue(struct net_device *ndev) +{ +	struct arc_emac_priv *priv = netdev_priv(ndev); +	unsigned int i; + +	for (i = 0; i < RX_BD_NUM; i++) { +		struct arc_emac_bd *rxbd = &priv->rxbd[i]; +		struct buffer_state *rx_buff = &priv->rx_buff[i]; + +		if (rx_buff->skb) { +			dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr), +					dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE); + +			/* return the sk_buff to system */ +			dev_kfree_skb_irq(rx_buff->skb); +		} + +		rxbd->info = 0; +		rxbd->data = 0; +		rx_buff->skb = NULL; +	} +} + +/**   * arc_emac_stop - Close the network device.   * @ndev:	Pointer to the network device.   * @@ -534,6 +596,10 @@ static int arc_emac_stop(struct net_device *ndev)  	/* Disable EMAC */  	arc_reg_clr(priv, R_CTRL, EN_MASK); +	/* Return the sk_buff to system */ +	arc_free_tx_queue(ndev); +	arc_free_rx_queue(ndev); +  	return 0;  } @@ -610,7 +676,6 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)  	dma_unmap_addr_set(&priv->tx_buff[*txbd_curr], addr, addr);  	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len); -	priv->tx_buff[*txbd_curr].skb = skb;  	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);  	/* Make sure pointer to data buffer is set */ @@ -620,6 +685,11 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len); +	/* Make sure info word is set */ +	wmb(); + +	priv->tx_buff[*txbd_curr].skb = skb; +  	/* Increment index to point to the next BD */  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM; diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c index ecc4a334c507..08a23e6b60e9 100644 --- a/drivers/net/ethernet/aurora/nb8800.c +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -302,7 +302,7 @@ static int nb8800_poll(struct napi_struct *napi, int budget)  	nb8800_tx_done(dev);  again: -	while (work < budget) { +	do {  		struct nb8800_rx_buf *rxb;  		unsigned int len; @@ -330,7 +330,7 @@ again:  		rxd->report = 0;  		last = next;  		work++; -	} +	} while (work < budget);  	if (work) {  		priv->rx_descs[last].desc.config |= DESC_EOC; @@ -1460,7 +1460,19 @@ static int nb8800_probe(struct platform_device *pdev)  		goto err_disable_clk;  	} -	priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); +	if (of_phy_is_fixed_link(pdev->dev.of_node)) { +		ret = of_phy_register_fixed_link(pdev->dev.of_node); +		if (ret < 0) { +			dev_err(&pdev->dev, "bad fixed-link spec\n"); +			goto err_free_bus; +		} +		priv->phy_node = of_node_get(pdev->dev.of_node); +	} + +	if (!priv->phy_node) +		priv->phy_node = of_parse_phandle(pdev->dev.of_node, +						  "phy-handle", 0); +  	if (!priv->phy_node) {  		dev_err(&pdev->dev, "no PHY specified\n");  		ret = -ENODEV; diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 8550df189ceb..19f7cd02e085 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -151,8 +151,11 @@ config BNX2X_VXLAN  config BGMAC  	tristate "BCMA bus GBit core support" -	depends on BCMA_HOST_SOC && HAS_DMA && (BCM47XX || ARCH_BCM_5301X) +	depends on BCMA && BCMA_HOST_SOC +	depends on HAS_DMA +	depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST  	select PHYLIB +	select FIXED_PHY  	---help---  	  This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.  	  They can be found on BCM47xx SoCs and provide gigabit ethernet. diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 27aa0802d87d..91874d24fd56 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -4896,9 +4896,9 @@ struct c2s_pri_trans_table_entry {   * cfc delete event data   */  struct cfc_del_event_data { -	u32 cid; -	u32 reserved0; -	u32 reserved1; +	__le32 cid; +	__le32 reserved0; +	__le32 reserved1;  }; @@ -5114,15 +5114,9 @@ struct vf_pf_channel_zone_trigger {   * zone that triggers the in-bound interrupt   */  struct trigger_vf_zone { -#if defined(__BIG_ENDIAN) -	u16 reserved1; -	u8 reserved0; -	struct vf_pf_channel_zone_trigger vf_pf_channel; -#elif defined(__LITTLE_ENDIAN)  	struct vf_pf_channel_zone_trigger vf_pf_channel;  	u8 reserved0;  	u16 reserved1; -#endif  	u32 reserved2;  }; @@ -5207,9 +5201,9 @@ struct e2_integ_data {   * set mac event data   */  struct eth_event_data { -	u32 echo; -	u32 reserved0; -	u32 reserved1; +	__le32 echo; +	__le32 reserved0; +	__le32 reserved1;  }; @@ -5219,9 +5213,9 @@ struct eth_event_data {  struct vf_pf_event_data {  	u8 vf_id;  	u8 reserved0; -	u16 reserved1; -	u32 msg_addr_lo; -	u32 msg_addr_hi; +	__le16 reserved1; +	__le32 msg_addr_lo; +	__le32 msg_addr_hi;  };  /* @@ -5230,9 +5224,9 @@ struct vf_pf_event_data {  struct vf_flr_event_data {  	u8 vf_id;  	u8 reserved0; -	u16 reserved1; -	u32 reserved2; -	u32 reserved3; +	__le16 reserved1; +	__le32 reserved2; +	__le32 reserved3;  };  /* @@ -5241,9 +5235,9 @@ struct vf_flr_event_data {  struct malicious_vf_event_data {  	u8 vf_id;  	u8 err_id; -	u16 reserved1; -	u32 reserved2; -	u32 reserved3; +	__le16 reserved1; +	__le32 reserved2; +	__le32 reserved3;  };  /* diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index d946bba43726..1fb80100e5e7 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -6185,26 +6185,80 @@ static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)  		shift -= 4;  		digit = ((num & mask) >> shift);  		if (digit == 0 && remove_leading_zeros) { -			mask = mask >> 4; -			continue; -		} else if (digit < 0xa) -			*str_ptr = digit + '0'; -		else -			*str_ptr = digit - 0xa + 'a'; -		remove_leading_zeros = 0; -		str_ptr++; -		(*len)--; +			*str_ptr = '0'; +		} else { +			if (digit < 0xa) +				*str_ptr = digit + '0'; +			else +				*str_ptr = digit - 0xa + 'a'; + +			remove_leading_zeros = 0; +			str_ptr++; +			(*len)--; +		}  		mask = mask >> 4;  		if (shift == 4*4) { +			if (remove_leading_zeros) { +				str_ptr++; +				(*len)--; +			}  			*str_ptr = '.';  			str_ptr++;  			(*len)--;  			remove_leading_zeros = 1;  		}  	} +	if (remove_leading_zeros) +		(*len)--;  	return 0;  } +static int bnx2x_3_seq_format_ver(u32 num, u8 *str, u16 *len) +{ +	u8 *str_ptr = str; +	u32 mask = 0x00f00000; +	u8 shift = 8*3; +	u8 digit; +	u8 remove_leading_zeros = 1; + +	if (*len < 10) { +		/* Need more than 10chars for this format */ +		*str_ptr = '\0'; +		(*len)--; +		return -EINVAL; +	} + +	while (shift > 0) { +		shift -= 4; +		digit = ((num & mask) >> shift); +		if (digit == 0 && remove_leading_zeros) { +			*str_ptr = '0'; +		} else { +			if (digit < 0xa) +				*str_ptr = digit + '0'; +			else +				*str_ptr = digit - 0xa + 'a'; + +			remove_leading_zeros = 0; +			str_ptr++; +			(*len)--; +		} +		mask = mask >> 4; +		if ((shift == 4*4) || (shift == 4*2)) { +			if (remove_leading_zeros) { +				str_ptr++; +				(*len)--; +			} +			*str_ptr = '.'; +			str_ptr++; +			(*len)--; +			remove_leading_zeros = 1; +		} +	} +	if (remove_leading_zeros) +		(*len)--; +	return 0; +}  static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)  { @@ -9677,8 +9731,9 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,  	if (bnx2x_is_8483x_8485x(phy)) {  		bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1); -		bnx2x_save_spirom_version(bp, port, fw_ver1 & 0xfff, -				phy->ver_addr); +		if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) +			fw_ver1 &= 0xfff; +		bnx2x_save_spirom_version(bp, port, fw_ver1, phy->ver_addr);  	} else {  		/* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */  		/* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */ @@ -9732,16 +9787,32 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,  static void bnx2x_848xx_set_led(struct bnx2x *bp,  				struct bnx2x_phy *phy)  { -	u16 val, offset, i; +	u16 val, led3_blink_rate, offset, i;  	static struct bnx2x_reg_set reg_set[] = {  		{MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED1_MASK, 0x0080},  		{MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED2_MASK, 0x0018},  		{MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED3_MASK, 0x0006}, -		{MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED3_BLINK, 0x0000},  		{MDIO_PMA_DEVAD, MDIO_PMA_REG_84823_CTL_SLOW_CLK_CNT_HIGH,  			MDIO_PMA_REG_84823_BLINK_RATE_VAL_15P9HZ},  		{MDIO_AN_DEVAD, 0xFFFB, 0xFFFD}  	}; + +	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) { +		/* Set LED5 source */ +		bnx2x_cl45_write(bp, phy, +				 MDIO_PMA_DEVAD, +				 MDIO_PMA_REG_8481_LED5_MASK, +				 0x90); +		led3_blink_rate = 0x000f; +	} else { +		led3_blink_rate = 0x0000; +	} +	/* Set LED3 BLINK */ +	bnx2x_cl45_write(bp, phy, +			 MDIO_PMA_DEVAD, +			 MDIO_PMA_REG_8481_LED3_BLINK, +			 led3_blink_rate); +  	/* PHYC_CTL_LED_CTL */  	bnx2x_cl45_read(bp, phy,  			MDIO_PMA_DEVAD, @@ -9749,6 +9820,9 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,  	val &= 0xFE00;  	val |= 0x0092; +	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) +		val |= 2 << 12; /* LED5 ON based on source */ +  	bnx2x_cl45_write(bp, phy,  			 MDIO_PMA_DEVAD,  			 MDIO_PMA_REG_8481_LINK_SIGNAL, val); @@ -9762,10 +9836,17 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,  	else  		offset = MDIO_PMA_REG_84823_CTL_LED_CTL_1; -	/* stretch_en for LED3*/ +	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) +		val = MDIO_PMA_REG_84858_ALLOW_GPHY_ACT | +		      MDIO_PMA_REG_84823_LED3_STRETCH_EN; +	else +		val = MDIO_PMA_REG_84823_LED3_STRETCH_EN; + +	/* stretch_en for LEDs */  	bnx2x_cl45_read_or_write(bp, phy, -				 MDIO_PMA_DEVAD, offset, -				 MDIO_PMA_REG_84823_LED3_STRETCH_EN); +				 MDIO_PMA_DEVAD, +				 offset, +				 val);  }  static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy, @@ -9775,7 +9856,7 @@ static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy,  	struct bnx2x *bp = params->bp;  	switch (action) {  	case PHY_INIT: -		if (!bnx2x_is_8483x_8485x(phy)) { +		if (bnx2x_is_8483x_8485x(phy)) {  			/* Save spirom version */  			bnx2x_save_848xx_spirom_version(phy, bp, params->port);  		} @@ -10036,15 +10117,20 @@ static int bnx2x_84858_cmd_hdlr(struct bnx2x_phy *phy,  static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,  				struct link_params *params, u16 fw_cmd, -				u16 cmd_args[], int argc) +				u16 cmd_args[], int argc, int process)  {  	int idx;  	u16 val;  	struct bnx2x *bp = params->bp; -	/* Write CMD_OPEN_OVERRIDE to STATUS reg */ -	bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, -			MDIO_848xx_CMD_HDLR_STATUS, -			PHY84833_STATUS_CMD_OPEN_OVERRIDE); +	int rc = 0; + +	if (process == PHY84833_MB_PROCESS2) { +		/* Write CMD_OPEN_OVERRIDE to STATUS reg */ +		bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, +				 MDIO_848xx_CMD_HDLR_STATUS, +				 PHY84833_STATUS_CMD_OPEN_OVERRIDE); +	} +  	for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) {  		bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,  				MDIO_848xx_CMD_HDLR_STATUS, &val); @@ -10054,15 +10140,27 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,  	}  	if (idx >= PHY848xx_CMDHDLR_WAIT) {  		DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n"); +		/* if the status is CMD_COMPLETE_PASS or CMD_COMPLETE_ERROR +		 * clear the status to CMD_CLEAR_COMPLETE +		 */ +		if (val == PHY84833_STATUS_CMD_COMPLETE_PASS || +		    val == PHY84833_STATUS_CMD_COMPLETE_ERROR) { +			bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, +					 MDIO_848xx_CMD_HDLR_STATUS, +					 PHY84833_STATUS_CMD_CLEAR_COMPLETE); +		}  		return -EINVAL;  	} - -	/* Prepare argument(s) and issue command */ -	for (idx = 0; idx < argc; idx++) { -		bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, -				MDIO_848xx_CMD_HDLR_DATA1 + idx, -				cmd_args[idx]); +	if (process == PHY84833_MB_PROCESS1 || +	    process == PHY84833_MB_PROCESS2) { +		/* Prepare argument(s) */ +		for (idx = 0; idx < argc; idx++) { +			bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, +					 MDIO_848xx_CMD_HDLR_DATA1 + idx, +					 cmd_args[idx]); +		}  	} +  	bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,  			MDIO_848xx_CMD_HDLR_COMMAND, fw_cmd);  	for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { @@ -10076,24 +10174,30 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,  	if ((idx >= PHY848xx_CMDHDLR_WAIT) ||  	    (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) {  		DP(NETIF_MSG_LINK, "FW cmd failed.\n"); -		return -EINVAL; +		rc = -EINVAL;  	} -	/* Gather returning data */ -	for (idx = 0; idx < argc; idx++) { -		bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, -				MDIO_848xx_CMD_HDLR_DATA1 + idx, -				&cmd_args[idx]); +	if (process == PHY84833_MB_PROCESS3 && rc == 0) { +		/* Gather returning data */ +		for (idx = 0; idx < argc; idx++) { +			bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, +					MDIO_848xx_CMD_HDLR_DATA1 + idx, +					&cmd_args[idx]); +		}  	} -	bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, -			MDIO_848xx_CMD_HDLR_STATUS, -			PHY84833_STATUS_CMD_CLEAR_COMPLETE); -	return 0; +	if (val == PHY84833_STATUS_CMD_COMPLETE_ERROR || +	    val == PHY84833_STATUS_CMD_COMPLETE_PASS) { +		bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, +				 MDIO_848xx_CMD_HDLR_STATUS, +				 PHY84833_STATUS_CMD_CLEAR_COMPLETE); +	} +	return rc;  }  static int bnx2x_848xx_cmd_hdlr(struct bnx2x_phy *phy,  				struct link_params *params,  				u16 fw_cmd, -				u16 cmd_args[], int argc) +					   u16 cmd_args[], int argc, +					   int process)  {  	struct bnx2x *bp = params->bp; @@ -10106,7 +10210,7 @@ static int bnx2x_848xx_cmd_hdlr(struct bnx2x_phy *phy,  					    argc);  	} else {  		return bnx2x_84833_cmd_hdlr(phy, params, fw_cmd, cmd_args, -					    argc); +					    argc, process);  	}  } @@ -10133,7 +10237,7 @@ static int bnx2x_848xx_pair_swap_cfg(struct bnx2x_phy *phy,  	status = bnx2x_848xx_cmd_hdlr(phy, params,  				      PHY848xx_CMD_SET_PAIR_SWAP, data, -				      PHY848xx_CMDHDLR_MAX_ARGS); +				      2, PHY84833_MB_PROCESS2);  	if (status == 0)  		DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data[1]); @@ -10222,8 +10326,8 @@ static int bnx2x_8483x_disable_eee(struct bnx2x_phy *phy,  	DP(NETIF_MSG_LINK, "Don't Advertise 10GBase-T EEE\n");  	/* Prevent Phy from working in EEE and advertising it */ -	rc = bnx2x_848xx_cmd_hdlr(phy, params, -				  PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1); +	rc = bnx2x_848xx_cmd_hdlr(phy, params, PHY848xx_CMD_SET_EEE_MODE, +				  &cmd_args, 1, PHY84833_MB_PROCESS1);  	if (rc) {  		DP(NETIF_MSG_LINK, "EEE disable failed.\n");  		return rc; @@ -10240,8 +10344,8 @@ static int bnx2x_8483x_enable_eee(struct bnx2x_phy *phy,  	struct bnx2x *bp = params->bp;  	u16 cmd_args = 1; -	rc = bnx2x_848xx_cmd_hdlr(phy, params, -				  PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1); +	rc = bnx2x_848xx_cmd_hdlr(phy, params, PHY848xx_CMD_SET_EEE_MODE, +				  &cmd_args, 1, PHY84833_MB_PROCESS1);  	if (rc) {  		DP(NETIF_MSG_LINK, "EEE enable failed.\n");  		return rc; @@ -10362,7 +10466,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,  		cmd_args[3] = PHY84833_CONSTANT_LATENCY;  		rc = bnx2x_848xx_cmd_hdlr(phy, params,  					  PHY848xx_CMD_SET_EEE_MODE, cmd_args, -					  PHY848xx_CMDHDLR_MAX_ARGS); +					  4, PHY84833_MB_PROCESS1);  		if (rc)  			DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");  	} @@ -10416,6 +10520,32 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,  		vars->eee_status &= ~SHMEM_EEE_SUPPORTED_MASK;  	} +	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) { +		/* Additional settings for jumbo packets in 1000BASE-T mode */ +		/* Allow rx extended length */ +		bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, +				MDIO_AN_REG_8481_AUX_CTRL, &val); +		val |= 0x4000; +		bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, +				 MDIO_AN_REG_8481_AUX_CTRL, val); +		/* TX FIFO Elasticity LSB */ +		bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, +				MDIO_AN_REG_8481_1G_100T_EXT_CTRL, &val); +		val |= 0x1; +		bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, +				 MDIO_AN_REG_8481_1G_100T_EXT_CTRL, val); +		/* TX FIFO Elasticity MSB */ +		/* Enable expansion register 0x46 (Pattern Generator status) */ +		bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, +				 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf46); + +		bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, +				MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, &val); +		val |= 0x4000; +		bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, +				 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, val); +	} +  	if (bnx2x_is_8483x_8485x(phy)) {  		/* Bring PHY out of super isolate mode as the final step. */  		bnx2x_cl45_read_and_write(bp, phy, @@ -10555,6 +10685,17 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,  	return link_up;  } +static int bnx2x_8485x_format_ver(u32 raw_ver, u8 *str, u16 *len) +{ +	int status = 0; +	u32 num; + +	num = ((raw_ver & 0xF80) >> 7) << 16 | ((raw_ver & 0x7F) << 8) | +	      ((raw_ver & 0xF000) >> 12); +	status = bnx2x_3_seq_format_ver(num, str, len); +	return status; +} +  static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)  {  	int status = 0; @@ -10651,10 +10792,25 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,  					0x0);  		} else { +			/* LED 1 OFF */  			bnx2x_cl45_write(bp, phy,  					 MDIO_PMA_DEVAD,  					 MDIO_PMA_REG_8481_LED1_MASK,  					 0x0); + +			if (phy->type == +				PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) { +				/* LED 2 OFF */ +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_LED2_MASK, +						 0x0); +				/* LED 3 OFF */ +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_LED3_MASK, +						 0x0); +			}  		}  		break;  	case LED_MODE_FRONT_PANEL_OFF: @@ -10713,6 +10869,19 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,  						 MDIO_PMA_REG_8481_SIGNAL_MASK,  						 0x0);  			} +			if (phy->type == +				PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) { +				/* LED 2 OFF */ +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_LED2_MASK, +						 0x0); +				/* LED 3 OFF */ +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_LED3_MASK, +						 0x0); +			}  		}  		break;  	case LED_MODE_ON: @@ -10776,6 +10945,25 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,  						params->port*4,  						NIG_MASK_MI_INT);  				} +			} +			if (phy->type == +			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) { +				/* Tell LED3 to constant on */ +				bnx2x_cl45_read(bp, phy, +						MDIO_PMA_DEVAD, +						MDIO_PMA_REG_8481_LINK_SIGNAL, +						&val); +				val &= ~(7<<6); +				val |= (2<<6);  /* A83B[8:6]= 2 */ +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_LINK_SIGNAL, +						 val); +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_LED3_MASK, +						 0x20); +			} else {  				bnx2x_cl45_write(bp, phy,  						 MDIO_PMA_DEVAD,  						 MDIO_PMA_REG_8481_SIGNAL_MASK, @@ -10854,6 +11042,17 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,  					 MDIO_PMA_REG_8481_LINK_SIGNAL,  					 val);  			if (phy->type == +			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) { +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_LED2_MASK, +						 0x18); +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_LED3_MASK, +						 0x06); +			} +			if (phy->type ==  			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) {  				/* Restore LED4 source to external link,  				 * and re-enable interrupts. @@ -11982,7 +12181,7 @@ static const struct bnx2x_phy phy_84858 = {  	.read_status	= (read_status_t)bnx2x_848xx_read_status,  	.link_reset	= (link_reset_t)bnx2x_848x3_link_reset,  	.config_loopback = (config_loopback_t)NULL, -	.format_fw_ver	= (format_fw_ver_t)bnx2x_848xx_format_ver, +	.format_fw_ver	= (format_fw_ver_t)bnx2x_8485x_format_ver,  	.hw_reset	= (hw_reset_t)bnx2x_84833_hw_reset_phy,  	.set_link_led	= (set_link_led_t)bnx2x_848xx_set_link_led,  	.phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func @@ -13807,8 +14006,10 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)  	if (CHIP_IS_E3(bp)) {  		struct bnx2x_phy *phy = ¶ms->phy[INT_PHY];  		bnx2x_set_aer_mmd(params, phy); -		if ((phy->supported & SUPPORTED_20000baseKR2_Full) && -		    (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)) +		if (((phy->req_line_speed == SPEED_AUTO_NEG) && +		     (phy->speed_cap_mask & +		      PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)) || +		    (phy->req_line_speed == SPEED_20000))  			bnx2x_check_kr2_wa(params, vars, phy);  		bnx2x_check_over_curr(params, vars);  		if (vars->rx_tx_asic_rst) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 6c4e3a69976f..2bf9c871144f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -5280,14 +5280,14 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,  {  	unsigned long ramrod_flags = 0;  	int rc = 0; -	u32 cid = elem->message.data.eth_event.echo & BNX2X_SWCID_MASK; +	u32 echo = le32_to_cpu(elem->message.data.eth_event.echo); +	u32 cid = echo & BNX2X_SWCID_MASK;  	struct bnx2x_vlan_mac_obj *vlan_mac_obj;  	/* Always push next commands out, don't wait here */  	__set_bit(RAMROD_CONT, &ramrod_flags); -	switch (le32_to_cpu((__force __le32)elem->message.data.eth_event.echo) -			    >> BNX2X_SWCID_SHIFT) { +	switch (echo >> BNX2X_SWCID_SHIFT) {  	case BNX2X_FILTER_MAC_PENDING:  		DP(BNX2X_MSG_SP, "Got SETUP_MAC completions\n");  		if (CNIC_LOADED(bp) && (cid == BNX2X_ISCSI_ETH_CID(bp))) @@ -5308,8 +5308,7 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,  		bnx2x_handle_mcast_eqe(bp);  		return;  	default: -		BNX2X_ERR("Unsupported classification command: %d\n", -			  elem->message.data.eth_event.echo); +		BNX2X_ERR("Unsupported classification command: 0x%x\n", echo);  		return;  	} @@ -5478,9 +5477,6 @@ static void bnx2x_eq_int(struct bnx2x *bp)  			goto next_spqe;  		} -		/* elem CID originates from FW; actually LE */ -		cid = SW_CID((__force __le32) -			     elem->message.data.cfc_del_event.cid);  		opcode = elem->message.opcode;  		/* handle eq element */ @@ -5503,6 +5499,10 @@ static void bnx2x_eq_int(struct bnx2x *bp)  			 * we may want to verify here that the bp state is  			 * HALTING  			 */ + +			/* elem CID originates from FW; actually LE */ +			cid = SW_CID(elem->message.data.cfc_del_event.cid); +  			DP(BNX2X_MSG_SP,  			   "got delete ramrod for MULTI[%d]\n", cid); @@ -5596,10 +5596,8 @@ static void bnx2x_eq_int(struct bnx2x *bp)  		      BNX2X_STATE_OPENING_WAIT4_PORT):  		case (EVENT_RING_OPCODE_RSS_UPDATE_RULES |  		      BNX2X_STATE_CLOSING_WAIT4_HALT): -			cid = elem->message.data.eth_event.echo & -				BNX2X_SWCID_MASK;  			DP(BNX2X_MSG_SP, "got RSS_UPDATE ramrod. CID %d\n", -			   cid); +			   SW_CID(elem->message.data.eth_event.echo));  			rss_raw->clear_pending(rss_raw);  			break; @@ -5684,7 +5682,7 @@ static void bnx2x_sp_task(struct work_struct *work)  		if (status & BNX2X_DEF_SB_IDX) {  			struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp); -		if (FCOE_INIT(bp) && +			if (FCOE_INIT(bp) &&  			    (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {  				/* Prevent local bottom-halves from running as  				 * we are going to change the local NAPI list. diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index 4dead49bd5cb..a43dea259b12 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -7296,6 +7296,8 @@ Theotherbitsarereservedandshouldbezero*/  #define MDIO_PMA_REG_84823_CTL_LED_CTL_1			0xa8e3  #define MDIO_PMA_REG_84833_CTL_LED_CTL_1			0xa8ec  #define MDIO_PMA_REG_84823_LED3_STRETCH_EN			0x0080 +/* BCM84858 only */ +#define MDIO_PMA_REG_84858_ALLOW_GPHY_ACT			0x8000  /* BCM84833 only */  #define MDIO_84833_TOP_CFG_FW_REV			0x400f @@ -7337,6 +7339,10 @@ Theotherbitsarereservedandshouldbezero*/  #define PHY84833_STATUS_CMD_NOT_OPEN_FOR_CMDS		0x0040  #define PHY84833_STATUS_CMD_CLEAR_COMPLETE		0x0080  #define PHY84833_STATUS_CMD_OPEN_OVERRIDE		0xa5a5 +/* Mailbox Process */ +#define PHY84833_MB_PROCESS1				1 +#define PHY84833_MB_PROCESS2				2 +#define PHY84833_MB_PROCESS3				3  /* Mailbox status set used by 84858 only */  #define PHY84858_STATUS_CMD_RECEIVED			0x0001 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 9d027348cd09..632daff117d3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -1672,11 +1672,12 @@ void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,  {  	unsigned long ramrod_flags = 0;  	int rc = 0; +	u32 echo = le32_to_cpu(elem->message.data.eth_event.echo);  	/* Always push next commands out, don't wait here */  	set_bit(RAMROD_CONT, &ramrod_flags); -	switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) { +	switch (echo >> BNX2X_SWCID_SHIFT) {  	case BNX2X_FILTER_MAC_PENDING:  		rc = vfq->mac_obj.complete(bp, &vfq->mac_obj, elem,  					   &ramrod_flags); @@ -1686,8 +1687,7 @@ void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,  					    &ramrod_flags);  		break;  	default: -		BNX2X_ERR("Unsupported classification command: %d\n", -			  elem->message.data.eth_event.echo); +		BNX2X_ERR("Unsupported classification command: 0x%x\n", echo);  		return;  	}  	if (rc < 0) @@ -1747,16 +1747,14 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)  	switch (opcode) {  	case EVENT_RING_OPCODE_CFC_DEL: -		cid = SW_CID((__force __le32) -			     elem->message.data.cfc_del_event.cid); +		cid = SW_CID(elem->message.data.cfc_del_event.cid);  		DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid);  		break;  	case EVENT_RING_OPCODE_CLASSIFICATION_RULES:  	case EVENT_RING_OPCODE_MULTICAST_RULES:  	case EVENT_RING_OPCODE_FILTERS_RULES:  	case EVENT_RING_OPCODE_RSS_UPDATE_RULES: -		cid = (elem->message.data.eth_event.echo & -		       BNX2X_SWCID_MASK); +		cid = SW_CID(elem->message.data.eth_event.echo);  		DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);  		break;  	case EVENT_RING_OPCODE_VF_FLR: diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 1374e5394a79..bfae300cf25f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -2187,8 +2187,10 @@ void bnx2x_vf_mbx_schedule(struct bnx2x *bp,  	/* Update VFDB with current message and schedule its handling */  	mutex_lock(&BP_VFDB(bp)->event_mutex); -	BP_VF_MBX(bp, vf_idx)->vf_addr_hi = vfpf_event->msg_addr_hi; -	BP_VF_MBX(bp, vf_idx)->vf_addr_lo = vfpf_event->msg_addr_lo; +	BP_VF_MBX(bp, vf_idx)->vf_addr_hi = +		le32_to_cpu(vfpf_event->msg_addr_hi); +	BP_VF_MBX(bp, vf_idx)->vf_addr_lo = +		le32_to_cpu(vfpf_event->msg_addr_lo);  	BP_VFDB(bp)->event_occur |= (1ULL << vf_idx);  	mutex_unlock(&BP_VFDB(bp)->event_mutex); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index df835f5e46d8..82f191382989 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -69,7 +69,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);  #define BNXT_RX_DMA_OFFSET NET_SKB_PAD  #define BNXT_RX_COPY_THRESH 256 -#define BNXT_TX_PUSH_THRESH 92 +#define BNXT_TX_PUSH_THRESH 164  enum board_idx {  	BCM57301, @@ -223,11 +223,12 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)  	}  	if (free_size == bp->tx_ring_size && length <= bp->tx_push_thresh) { -		struct tx_push_bd *push = txr->tx_push; -		struct tx_bd *tx_push = &push->txbd1; -		struct tx_bd_ext *tx_push1 = &push->txbd2; -		void *pdata = tx_push1 + 1; -		int j; +		struct tx_push_buffer *tx_push_buf = txr->tx_push; +		struct tx_push_bd *tx_push = &tx_push_buf->push_bd; +		struct tx_bd_ext *tx_push1 = &tx_push->txbd2; +		void *pdata = tx_push_buf->data; +		u64 *end; +		int j, push_len;  		/* Set COAL_NOW to be ready quickly for the next push */  		tx_push->tx_bd_len_flags_type = @@ -247,6 +248,10 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)  		tx_push1->tx_bd_cfa_meta = cpu_to_le32(vlan_tag_flags);  		tx_push1->tx_bd_cfa_action = cpu_to_le32(cfa_action); +		end = pdata + length; +		end = PTR_ALIGN(end, 8) - 1; +		*end = 0; +  		skb_copy_from_linear_data(skb, pdata, len);  		pdata += len;  		for (j = 0; j < last_frag; j++) { @@ -261,22 +266,29 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)  			pdata += skb_frag_size(frag);  		} -		memcpy(txbd, tx_push, sizeof(*txbd)); +		txbd->tx_bd_len_flags_type = tx_push->tx_bd_len_flags_type; +		txbd->tx_bd_haddr = txr->data_mapping;  		prod = NEXT_TX(prod);  		txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];  		memcpy(txbd, tx_push1, sizeof(*txbd));  		prod = NEXT_TX(prod); -		push->doorbell = +		tx_push->doorbell =  			cpu_to_le32(DB_KEY_TX_PUSH | DB_LONG_TX_PUSH | prod);  		txr->tx_prod = prod;  		netdev_tx_sent_queue(txq, skb->len); -		__iowrite64_copy(txr->tx_doorbell, push, -				 (length + sizeof(*push) + 8) / 8); +		push_len = (length + sizeof(*tx_push) + 7) / 8; +		if (push_len > 16) { +			__iowrite64_copy(txr->tx_doorbell, tx_push_buf, 16); +			__iowrite64_copy(txr->tx_doorbell + 4, tx_push_buf + 1, +					 push_len - 16); +		} else { +			__iowrite64_copy(txr->tx_doorbell, tx_push_buf, +					 push_len); +		}  		tx_buf->is_push = 1; -  		goto tx_done;  	} @@ -1490,10 +1502,11 @@ static void bnxt_free_tx_skbs(struct bnxt *bp)  			last = tx_buf->nr_frags;  			j += 2; -			for (k = 0; k < last; k++, j = NEXT_TX(j)) { +			for (k = 0; k < last; k++, j++) { +				int ring_idx = j & bp->tx_ring_mask;  				skb_frag_t *frag = &skb_shinfo(skb)->frags[k]; -				tx_buf = &txr->tx_buf_ring[j]; +				tx_buf = &txr->tx_buf_ring[ring_idx];  				dma_unmap_page(  					&pdev->dev,  					dma_unmap_addr(tx_buf, mapping), @@ -1752,7 +1765,7 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)  		push_size  = L1_CACHE_ALIGN(sizeof(struct tx_push_bd) +  					bp->tx_push_thresh); -		if (push_size > 128) { +		if (push_size > 256) {  			push_size = 0;  			bp->tx_push_thresh = 0;  		} @@ -1771,7 +1784,6 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)  			return rc;  		if (bp->tx_push_size) { -			struct tx_bd *txbd;  			dma_addr_t mapping;  			/* One pre-allocated DMA buffer to backup @@ -1785,13 +1797,11 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)  			if (!txr->tx_push)  				return -ENOMEM; -			txbd = &txr->tx_push->txbd1; -  			mapping = txr->tx_push_mapping +  				sizeof(struct tx_push_bd); -			txbd->tx_bd_haddr = cpu_to_le64(mapping); +			txr->data_mapping = cpu_to_le64(mapping); -			memset(txbd + 1, 0, sizeof(struct tx_bd_ext)); +			memset(txr->tx_push, 0, sizeof(struct tx_push_bd));  		}  		ring->queue_id = bp->q_info[j].queue_id;  		if (i % bp->tx_nr_rings_per_tc == (bp->tx_nr_rings_per_tc - 1)) @@ -3406,7 +3416,7 @@ static int hwrm_ring_free_send_msg(struct bnxt *bp,  	struct hwrm_ring_free_output *resp = bp->hwrm_cmd_resp_addr;  	u16 error_code; -	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_FREE, -1, -1); +	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_FREE, cmpl_ring_id, -1);  	req.ring_type = ring_type;  	req.ring_id = cpu_to_le16(ring->fw_ring_id); @@ -4545,20 +4555,18 @@ static int bnxt_update_phy_setting(struct bnxt *bp)  	if (!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) &&  	    link_info->force_pause_setting != link_info->req_flow_ctrl)  		update_pause = true; -	if (link_info->req_duplex != link_info->duplex_setting) -		update_link = true;  	if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {  		if (BNXT_AUTO_MODE(link_info->auto_mode))  			update_link = true;  		if (link_info->req_link_speed != link_info->force_link_speed)  			update_link = true; +		if (link_info->req_duplex != link_info->duplex_setting) +			update_link = true;  	} else {  		if (link_info->auto_mode == BNXT_LINK_AUTO_NONE)  			update_link = true;  		if (link_info->advertising != link_info->auto_link_speeds)  			update_link = true; -		if (link_info->req_link_speed != link_info->auto_link_speed) -			update_link = true;  	}  	if (update_link) @@ -4635,7 +4643,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)  	if (link_re_init) {  		rc = bnxt_update_phy_setting(bp);  		if (rc) -			goto open_err; +			netdev_warn(bp->dev, "failed to update phy settings\n");  	}  	if (irq_re_init) { @@ -4653,6 +4661,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)  	/* Enable TX queues */  	bnxt_tx_enable(bp);  	mod_timer(&bp->timer, jiffies + bp->current_interval); +	bnxt_update_link(bp, true);  	return 0; @@ -4819,8 +4828,6 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)  		stats->multicast += le64_to_cpu(hw_stats->rx_mcast_pkts); -		stats->rx_dropped += le64_to_cpu(hw_stats->rx_drop_pkts); -  		stats->tx_dropped += le64_to_cpu(hw_stats->tx_drop_pkts);  	} @@ -5671,22 +5678,16 @@ static int bnxt_probe_phy(struct bnxt *bp)  	}  	/*initialize the ethool setting copy with NVM settings */ -	if (BNXT_AUTO_MODE(link_info->auto_mode)) -		link_info->autoneg |= BNXT_AUTONEG_SPEED; - -	if (link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) { -		if (link_info->auto_pause_setting == BNXT_LINK_PAUSE_BOTH) -			link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; +	if (BNXT_AUTO_MODE(link_info->auto_mode)) { +		link_info->autoneg = BNXT_AUTONEG_SPEED | +				     BNXT_AUTONEG_FLOW_CTRL; +		link_info->advertising = link_info->auto_link_speeds;  		link_info->req_flow_ctrl = link_info->auto_pause_setting; -	} else if (link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) { +	} else { +		link_info->req_link_speed = link_info->force_link_speed; +		link_info->req_duplex = link_info->duplex_setting;  		link_info->req_flow_ctrl = link_info->force_pause_setting;  	} -	link_info->req_duplex = link_info->duplex_setting; -	if (link_info->autoneg & BNXT_AUTONEG_SPEED) -		link_info->req_link_speed = link_info->auto_link_speed; -	else -		link_info->req_link_speed = link_info->force_link_speed; -	link_info->advertising = link_info->auto_link_speeds;  	snprintf(phy_ver, PHY_VER_STR_LEN, " ph %d.%d.%d",  		 link_info->phy_ver[0],  		 link_info->phy_ver[1], diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 8af3ca8efcef..2be51b332652 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -411,8 +411,8 @@ struct rx_tpa_end_cmp_ext {  #define BNXT_NUM_TESTS(bp)	0 -#define BNXT_DEFAULT_RX_RING_SIZE	1023 -#define BNXT_DEFAULT_TX_RING_SIZE	512 +#define BNXT_DEFAULT_RX_RING_SIZE	511 +#define BNXT_DEFAULT_TX_RING_SIZE	511  #define MAX_TPA		64 @@ -523,10 +523,16 @@ struct bnxt_ring_struct {  struct tx_push_bd {  	__le32			doorbell; -	struct tx_bd		txbd1; +	__le32			tx_bd_len_flags_type; +	u32			tx_bd_opaque;  	struct tx_bd_ext	txbd2;  }; +struct tx_push_buffer { +	struct tx_push_bd	push_bd; +	u32			data[25]; +}; +  struct bnxt_tx_ring_info {  	struct bnxt_napi	*bnapi;  	u16			tx_prod; @@ -538,8 +544,9 @@ struct bnxt_tx_ring_info {  	dma_addr_t		tx_desc_mapping[MAX_TX_PAGES]; -	struct tx_push_bd	*tx_push; +	struct tx_push_buffer	*tx_push;  	dma_addr_t		tx_push_mapping; +	__le64			data_mapping;  #define BNXT_DEV_STATE_CLOSING	0x1  	u32			dev_state; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 922b898e7a32..3238817dfd5f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -486,15 +486,8 @@ static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info)  		speed_mask |= SUPPORTED_2500baseX_Full;  	if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)  		speed_mask |= SUPPORTED_10000baseT_Full; -	/* TODO: support 25GB, 50GB with different cable type */ -	if (fw_speeds & BNXT_LINK_SPEED_MSK_20GB) -		speed_mask |= SUPPORTED_20000baseMLD2_Full | -			SUPPORTED_20000baseKR2_Full;  	if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) -		speed_mask |= SUPPORTED_40000baseKR4_Full | -			SUPPORTED_40000baseCR4_Full | -			SUPPORTED_40000baseSR4_Full | -			SUPPORTED_40000baseLR4_Full; +		speed_mask |= SUPPORTED_40000baseCR4_Full;  	return speed_mask;  } @@ -514,15 +507,8 @@ static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info)  		speed_mask |= ADVERTISED_2500baseX_Full;  	if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)  		speed_mask |= ADVERTISED_10000baseT_Full; -	/* TODO: how to advertise 20, 25, 40, 50GB with different cable type ?*/ -	if (fw_speeds & BNXT_LINK_SPEED_MSK_20GB) -		speed_mask |= ADVERTISED_20000baseMLD2_Full | -			      ADVERTISED_20000baseKR2_Full;  	if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) -		speed_mask |= ADVERTISED_40000baseKR4_Full | -			      ADVERTISED_40000baseCR4_Full | -			      ADVERTISED_40000baseSR4_Full | -			      ADVERTISED_40000baseLR4_Full; +		speed_mask |= ADVERTISED_40000baseCR4_Full;  	return speed_mask;  } @@ -557,11 +543,12 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)  	u16 ethtool_speed;  	cmd->supported = bnxt_fw_to_ethtool_support_spds(link_info); +	cmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;  	if (link_info->auto_link_speeds)  		cmd->supported |= SUPPORTED_Autoneg; -	if (BNXT_AUTO_MODE(link_info->auto_mode)) { +	if (link_info->autoneg) {  		cmd->advertising =  			bnxt_fw_to_ethtool_advertised_spds(link_info);  		cmd->advertising |= ADVERTISED_Autoneg; @@ -570,28 +557,16 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)  		cmd->autoneg = AUTONEG_DISABLE;  		cmd->advertising = 0;  	} -	if (link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) { +	if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) {  		if ((link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) ==  		    BNXT_LINK_PAUSE_BOTH) {  			cmd->advertising |= ADVERTISED_Pause; -			cmd->supported |= SUPPORTED_Pause;  		} else {  			cmd->advertising |= ADVERTISED_Asym_Pause; -			cmd->supported |= SUPPORTED_Asym_Pause;  			if (link_info->auto_pause_setting &  			    BNXT_LINK_PAUSE_RX)  				cmd->advertising |= ADVERTISED_Pause;  		} -	} else if (link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) { -		if ((link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) == -		    BNXT_LINK_PAUSE_BOTH) { -			cmd->supported |= SUPPORTED_Pause; -		} else { -			cmd->supported |= SUPPORTED_Asym_Pause; -			if (link_info->force_pause_setting & -			    BNXT_LINK_PAUSE_RX) -				cmd->supported |= SUPPORTED_Pause; -		}  	}  	cmd->port = PORT_NONE; @@ -670,6 +645,9 @@ static u16 bnxt_get_fw_auto_link_speeds(u32 advertising)  	if (advertising & ADVERTISED_10000baseT_Full)  		fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; +	if (advertising & ADVERTISED_40000baseCR4_Full) +		fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; +  	return fw_speed_mask;  } @@ -729,7 +707,7 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)  		speed = ethtool_cmd_speed(cmd);  		link_info->req_link_speed = bnxt_get_fw_speed(dev, speed);  		link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; -		link_info->autoneg &= ~BNXT_AUTONEG_SPEED; +		link_info->autoneg = 0;  		link_info->advertising = 0;  	} @@ -748,8 +726,7 @@ static void bnxt_get_pauseparam(struct net_device *dev,  	if (BNXT_VF(bp))  		return; -	epause->autoneg = !!(link_info->auto_pause_setting & -			     BNXT_LINK_PAUSE_BOTH); +	epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL);  	epause->rx_pause = ((link_info->pause & BNXT_LINK_PAUSE_RX) != 0);  	epause->tx_pause = ((link_info->pause & BNXT_LINK_PAUSE_TX) != 0);  } @@ -765,6 +742,9 @@ static int bnxt_set_pauseparam(struct net_device *dev,  		return rc;  	if (epause->autoneg) { +		if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) +			return -EINVAL; +  		link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;  		link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_BOTH;  	} else { diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index b15a60d787c7..d7e01a74e927 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2445,8 +2445,7 @@ static void bcmgenet_irq_task(struct work_struct *work)  	}  	/* Link UP/DOWN event */ -	if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && -	    (priv->irq0_stat & UMAC_IRQ_LINK_EVENT)) { +	if (priv->irq0_stat & UMAC_IRQ_LINK_EVENT) {  		phy_mac_interrupt(priv->phydev,  				  !!(priv->irq0_stat & UMAC_IRQ_LINK_UP));  		priv->irq0_stat &= ~UMAC_IRQ_LINK_EVENT; diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 0d775964b060..457c3bc8cfff 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -401,7 +401,7 @@ int bcmgenet_mii_probe(struct net_device *dev)  	 * Ethernet MAC ISRs  	 */  	if (priv->internal_phy) -		priv->mii_bus->irq[phydev->mdio.addr] = PHY_IGNORE_INTERRUPT; +		priv->phydev->irq = PHY_IGNORE_INTERRUPT;  	return 0;  } diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 9293675df7ba..3010080cfeee 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -7831,6 +7831,14 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,  	return ret;  } +static bool tg3_tso_bug_gso_check(struct tg3_napi *tnapi, struct sk_buff *skb) +{ +	/* Check if we will never have enough descriptors, +	 * as gso_segs can be more than current ring size +	 */ +	return skb_shinfo(skb)->gso_segs < tnapi->tx_pending / 3; +} +  static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *);  /* Use GSO to workaround all TSO packets that meet HW bug conditions @@ -7934,14 +7942,19 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)  		 * vlan encapsulated.  		 */  		if (skb->protocol == htons(ETH_P_8021Q) || -		    skb->protocol == htons(ETH_P_8021AD)) -			return tg3_tso_bug(tp, tnapi, txq, skb); +		    skb->protocol == htons(ETH_P_8021AD)) { +			if (tg3_tso_bug_gso_check(tnapi, skb)) +				return tg3_tso_bug(tp, tnapi, txq, skb); +			goto drop; +		}  		if (!skb_is_gso_v6(skb)) {  			if (unlikely((ETH_HLEN + hdr_len) > 80) && -			    tg3_flag(tp, TSO_BUG)) -				return tg3_tso_bug(tp, tnapi, txq, skb); - +			    tg3_flag(tp, TSO_BUG)) { +				if (tg3_tso_bug_gso_check(tnapi, skb)) +					return tg3_tso_bug(tp, tnapi, txq, skb); +				goto drop; +			}  			ip_csum = iph->check;  			ip_tot_len = iph->tot_len;  			iph->check = 0; @@ -8073,7 +8086,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)  	if (would_hit_hwbug) {  		tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i); -		if (mss) { +		if (mss && tg3_tso_bug_gso_check(tnapi, skb)) {  			/* If it's a TSO packet, do GSO instead of  			 * allocating and copying to a large linear SKB  			 */ @@ -12016,7 +12029,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,  	int ret;  	u32 offset, len, b_offset, odd_len;  	u8 *buf; -	__be32 start, end; +	__be32 start = 0, end;  	if (tg3_flag(tp, NO_NVRAM) ||  	    eeprom->magic != TG3_EEPROM_MAGIC) diff --git a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c index 04b0d16b210e..95bc470ae441 100644 --- a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c +++ b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c @@ -987,7 +987,7 @@ bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf)  	if (!list_empty(&rxf->ucast_pending_add_q)) {  		mac = list_first_entry(&rxf->ucast_pending_add_q,  				       struct bna_mac, qe); -		list_add_tail(&mac->qe, &rxf->ucast_active_q); +		list_move_tail(&mac->qe, &rxf->ucast_active_q);  		bna_bfi_ucast_req(rxf, mac, BFI_ENET_H2I_MAC_UCAST_ADD_REQ);  		return 1;  	} diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 9d9984a87d42..50c94104f19c 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2823,7 +2823,7 @@ static int macb_probe(struct platform_device *pdev)  	struct device_node *np = pdev->dev.of_node;  	struct device_node *phy_node;  	const struct macb_config *macb_config = NULL; -	struct clk *pclk, *hclk, *tx_clk; +	struct clk *pclk, *hclk = NULL, *tx_clk = NULL;  	unsigned int queue_mask, num_queues;  	struct macb_platform_data *pdata;  	bool native_io; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index b89504405b72..34d269cd5579 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1526,7 +1526,6 @@ static int liquidio_ptp_gettime(struct ptp_clock_info *ptp,  				struct timespec64 *ts)  {  	u64 ns; -	u32 remainder;  	unsigned long flags;  	struct lio *lio = container_of(ptp, struct lio, ptp_info);  	struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; @@ -1536,8 +1535,7 @@ static int liquidio_ptp_gettime(struct ptp_clock_info *ptp,  	ns += lio->ptp_adjust;  	spin_unlock_irqrestore(&lio->ptp_lock, flags); -	ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder); -	ts->tv_nsec = remainder; +	*ts = ns_to_timespec64(ns);  	return 0;  } @@ -1685,7 +1683,7 @@ static int octeon_setup_droq(struct octeon_device *oct, int q_no, int num_descs,  	dev_dbg(&oct->pci_dev->dev, "Creating Droq: %d\n", q_no);  	/* droq creation and local register settings. */  	ret_val = octeon_create_droq(oct, q_no, num_descs, desc_size, app_ctx); -	if (ret_val == -1) +	if (ret_val < 0)  		return ret_val;  	if (ret_val == 1) { @@ -2526,7 +2524,7 @@ static void handle_timestamp(struct octeon_device *oct,  	octeon_swap_8B_data(&resp->timestamp, 1); -	if (unlikely((skb_shinfo(skb)->tx_flags | SKBTX_IN_PROGRESS) != 0)) { +	if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) != 0)) {  		struct skb_shared_hwtstamps ts;  		u64 ns = resp->timestamp; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index 4dba86eaa045..174072b3740b 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -983,5 +983,5 @@ int octeon_create_droq(struct octeon_device *oct,  create_droq_fail:  	octeon_delete_droq(oct, q_no); -	return -1; +	return -ENOMEM;  } diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index 688828865c48..34e9acea8747 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -116,6 +116,15 @@  #define NIC_PF_INTR_ID_MBOX0		8  #define NIC_PF_INTR_ID_MBOX1		9 +/* Minimum FIFO level before all packets for the CQ are dropped + * + * This value ensures that once a packet has been "accepted" + * for reception it will not get dropped due to non-availability + * of CQ descriptor. An errata in HW mandates this value to be + * atleast 0x100. + */ +#define NICPF_CQM_MIN_DROP_LEVEL       0x100 +  /* Global timer for CQ timer thresh interrupts   * Calculated for SCLK of 700Mhz   * value written should be a 1/16th of what is expected diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c index 4dded90076c8..95f17f8cadac 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_main.c +++ b/drivers/net/ethernet/cavium/thunder/nic_main.c @@ -304,6 +304,7 @@ static void nic_set_lmac_vf_mapping(struct nicpf *nic)  static void nic_init_hw(struct nicpf *nic)  {  	int i; +	u64 cqm_cfg;  	/* Enable NIC HW block */  	nic_reg_write(nic, NIC_PF_CFG, 0x3); @@ -340,6 +341,11 @@ static void nic_init_hw(struct nicpf *nic)  	/* Enable VLAN ethertype matching and stripping */  	nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7,  		      (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q); + +	/* Check if HW expected value is higher (could be in future chips) */ +	cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG); +	if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL) +		nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL);  }  /* Channel parse index configuration */ diff --git a/drivers/net/ethernet/cavium/thunder/nic_reg.h b/drivers/net/ethernet/cavium/thunder/nic_reg.h index dd536be20193..afb10e326b4f 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_reg.h +++ b/drivers/net/ethernet/cavium/thunder/nic_reg.h @@ -21,7 +21,7 @@  #define   NIC_PF_TCP_TIMER			(0x0060)  #define   NIC_PF_BP_CFG				(0x0080)  #define   NIC_PF_RRM_CFG			(0x0088) -#define   NIC_PF_CQM_CF				(0x00A0) +#define   NIC_PF_CQM_CFG			(0x00A0)  #define   NIC_PF_CNM_CF				(0x00A8)  #define   NIC_PF_CNM_STATUS			(0x00B0)  #define   NIC_PF_CQ_AVG_CFG			(0x00C0) diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index c24cb2a86a42..a009bc30dc4d 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -574,8 +574,7 @@ static inline void nicvf_set_rxhash(struct net_device *netdev,  static void nicvf_rcv_pkt_handler(struct net_device *netdev,  				  struct napi_struct *napi, -				  struct cmp_queue *cq, -				  struct cqe_rx_t *cqe_rx, int cqe_type) +				  struct cqe_rx_t *cqe_rx)  {  	struct sk_buff *skb;  	struct nicvf *nic = netdev_priv(netdev); @@ -591,7 +590,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,  	}  	/* Check for errors */ -	err = nicvf_check_cqe_rx_errs(nic, cq, cqe_rx); +	err = nicvf_check_cqe_rx_errs(nic, cqe_rx);  	if (err && !cqe_rx->rb_cnt)  		return; @@ -682,8 +681,7 @@ loop:  			   cq_idx, cq_desc->cqe_type);  		switch (cq_desc->cqe_type) {  		case CQE_TYPE_RX: -			nicvf_rcv_pkt_handler(netdev, napi, cq, -					      cq_desc, CQE_TYPE_RX); +			nicvf_rcv_pkt_handler(netdev, napi, cq_desc);  			work_done++;  		break;  		case CQE_TYPE_SEND: @@ -1125,7 +1123,6 @@ int nicvf_stop(struct net_device *netdev)  	/* Clear multiqset info */  	nic->pnicvf = nic; -	nic->sqs_count = 0;  	return 0;  } @@ -1354,6 +1351,9 @@ void nicvf_update_stats(struct nicvf *nic)  	drv_stats->tx_frames_ok = stats->tx_ucast_frames_ok +  				  stats->tx_bcast_frames_ok +  				  stats->tx_mcast_frames_ok; +	drv_stats->rx_frames_ok = stats->rx_ucast_frames + +				  stats->rx_bcast_frames + +				  stats->rx_mcast_frames;  	drv_stats->rx_drops = stats->rx_drop_red +  			      stats->rx_drop_overrun;  	drv_stats->tx_drops = stats->tx_drops; @@ -1538,6 +1538,9 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	nicvf_send_vf_struct(nic); +	if (!pass1_silicon(nic->pdev)) +		nic->hw_tso = true; +  	/* Check if this VF is in QS only mode */  	if (nic->sqs_mode)  		return 0; @@ -1557,9 +1560,6 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; -	if (!pass1_silicon(nic->pdev)) -		nic->hw_tso = true; -  	netdev->netdev_ops = &nicvf_netdev_ops;  	netdev->watchdog_timeo = NICVF_TX_TIMEOUT; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index d0d1b5490061..767347b1f631 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -1329,16 +1329,12 @@ void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx)  }  /* Check for errors in the receive cmp.queue entry */ -int nicvf_check_cqe_rx_errs(struct nicvf *nic, -			    struct cmp_queue *cq, struct cqe_rx_t *cqe_rx) +int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)  {  	struct nicvf_hw_stats *stats = &nic->hw_stats; -	struct nicvf_drv_stats *drv_stats = &nic->drv_stats; -	if (!cqe_rx->err_level && !cqe_rx->err_opcode) { -		drv_stats->rx_frames_ok++; +	if (!cqe_rx->err_level && !cqe_rx->err_opcode)  		return 0; -	}  	if (netif_msg_rx_err(nic))  		netdev_err(nic->netdev, diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h index c5030a7f213a..6673e1133523 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h @@ -338,8 +338,7 @@ u64  nicvf_queue_reg_read(struct nicvf *nic,  /* Stats */  void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx);  void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx); -int nicvf_check_cqe_rx_errs(struct nicvf *nic, -			    struct cmp_queue *cq, struct cqe_rx_t *cqe_rx); +int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx);  int nicvf_check_cqe_tx_errs(struct nicvf *nic,  			    struct cmp_queue *cq, struct cqe_send_t *cqe_tx);  #endif /* NICVF_QUEUES_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c index ee04caa6c4d8..a89721fad633 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c @@ -681,6 +681,24 @@ int t3_seeprom_wp(struct adapter *adapter, int enable)  	return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);  } +static int vpdstrtouint(char *s, int len, unsigned int base, unsigned int *val) +{ +	char tok[len + 1]; + +	memcpy(tok, s, len); +	tok[len] = 0; +	return kstrtouint(strim(tok), base, val); +} + +static int vpdstrtou16(char *s, int len, unsigned int base, u16 *val) +{ +	char tok[len + 1]; + +	memcpy(tok, s, len); +	tok[len] = 0; +	return kstrtou16(strim(tok), base, val); +} +  /**   *	get_vpd_params - read VPD parameters from VPD EEPROM   *	@adapter: adapter to read @@ -709,19 +727,19 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)  			return ret;  	} -	ret = kstrtouint(vpd.cclk_data, 10, &p->cclk); +	ret = vpdstrtouint(vpd.cclk_data, vpd.cclk_len, 10, &p->cclk);  	if (ret)  		return ret; -	ret = kstrtouint(vpd.mclk_data, 10, &p->mclk); +	ret = vpdstrtouint(vpd.mclk_data, vpd.mclk_len, 10, &p->mclk);  	if (ret)  		return ret; -	ret = kstrtouint(vpd.uclk_data, 10, &p->uclk); +	ret = vpdstrtouint(vpd.uclk_data, vpd.uclk_len, 10, &p->uclk);  	if (ret)  		return ret; -	ret = kstrtouint(vpd.mdc_data, 10, &p->mdc); +	ret = vpdstrtouint(vpd.mdc_data, vpd.mdc_len, 10, &p->mdc);  	if (ret)  		return ret; -	ret = kstrtouint(vpd.mt_data, 10, &p->mem_timing); +	ret = vpdstrtouint(vpd.mt_data, vpd.mt_len, 10, &p->mem_timing);  	if (ret)  		return ret;  	memcpy(p->sn, vpd.sn_data, SERNUM_LEN); @@ -733,10 +751,12 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)  	} else {  		p->port_type[0] = hex_to_bin(vpd.port0_data[0]);  		p->port_type[1] = hex_to_bin(vpd.port1_data[0]); -		ret = kstrtou16(vpd.xaui0cfg_data, 16, &p->xauicfg[0]); +		ret = vpdstrtou16(vpd.xaui0cfg_data, vpd.xaui0cfg_len, 16, +				  &p->xauicfg[0]);  		if (ret)  			return ret; -		ret = kstrtou16(vpd.xaui1cfg_data, 16, &p->xauicfg[1]); +		ret = vpdstrtou16(vpd.xaui1cfg_data, vpd.xaui1cfg_len, 16, +				  &p->xauicfg[1]);  		if (ret)  			return ret;  	} diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index a072d341e205..1d2d1da40c80 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -1021,6 +1021,8 @@ struct cpl_l2t_write_req {  #define L2T_W_NOREPLY_V(x) ((x) << L2T_W_NOREPLY_S)  #define L2T_W_NOREPLY_F    L2T_W_NOREPLY_V(1U) +#define CPL_L2T_VLAN_NONE 0xfff +  struct cpl_l2t_write_rpl {  	union opcode_tid ot;  	u8 status; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index a8dda635456d..06bc2d2e7a73 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -165,6 +165,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN  	CH_PCI_ID_TABLE_FENTRY(0x5098),	/* Custom 2x40G QSFP */  	CH_PCI_ID_TABLE_FENTRY(0x5099),	/* Custom 2x40G QSFP */  	CH_PCI_ID_TABLE_FENTRY(0x509a),	/* Custom T520-CR */ +	CH_PCI_ID_TABLE_FENTRY(0x509b),	/* Custom T540-CR LOM */  	/* T6 adapters:  	 */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index a32de30ea663..c8661c77b4e3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -561,6 +561,7 @@ enum fw_flowc_mnem {  	FW_FLOWC_MNEM_SNDBUF,  	FW_FLOWC_MNEM_MSS,  	FW_FLOWC_MNEM_TXDATAPLEN_MAX, +	FW_FLOWC_MNEM_SCHEDCLASS = 11,  };  struct fw_flowc_mnemval { diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 1671fa3332c2..7ba6d530b0c0 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -33,7 +33,7 @@  #define DRV_NAME		"enic"  #define DRV_DESCRIPTION		"Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION		"2.3.0.12" +#define DRV_VERSION		"2.3.0.20"  #define DRV_COPYRIGHT		"Copyright 2008-2013 Cisco Systems, Inc"  #define ENIC_BARS_MAX		6 diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c index 1ffd1050860b..1fdf5fe12a95 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_dev.c +++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c @@ -298,7 +298,8 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,  			  int wait)  {  	struct devcmd2_controller *dc2c = vdev->devcmd2; -	struct devcmd2_result *result = dc2c->result + dc2c->next_result; +	struct devcmd2_result *result; +	u8 color;  	unsigned int i;  	int delay, err;  	u32 fetch_index, new_posted; @@ -336,13 +337,17 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,  	if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT)  		return 0; +	result = dc2c->result + dc2c->next_result; +	color = dc2c->color; + +	dc2c->next_result++; +	if (dc2c->next_result == dc2c->result_size) { +		dc2c->next_result = 0; +		dc2c->color = dc2c->color ? 0 : 1; +	} +  	for (delay = 0; delay < wait; delay++) { -		if (result->color == dc2c->color) { -			dc2c->next_result++; -			if (dc2c->next_result == dc2c->result_size) { -				dc2c->next_result = 0; -				dc2c->color = dc2c->color ? 0 : 1; -			} +		if (result->color == color) {  			if (result->error) {  				err = result->error;  				if (err != ERR_ECMDUNKNOWN || diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index cf94b72dbacd..48d91941408d 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -128,7 +128,6 @@ struct board_info {  	struct resource *data_res;  	struct resource	*addr_req;   /* resources requested */  	struct resource *data_req; -	struct resource *irq_res;  	int		 irq_wake; @@ -1300,22 +1299,16 @@ static int  dm9000_open(struct net_device *dev)  {  	struct board_info *db = netdev_priv(dev); -	unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;  	if (netif_msg_ifup(db))  		dev_dbg(db->dev, "enabling %s\n", dev->name); -	/* If there is no IRQ type specified, default to something that -	 * may work, and tell the user that this is a problem */ - -	if (irqflags == IRQF_TRIGGER_NONE) -		irqflags = irq_get_trigger_type(dev->irq); - -	if (irqflags == IRQF_TRIGGER_NONE) +	/* If there is no IRQ type specified, tell the user that this is a +	 * problem +	 */ +	if (irq_get_trigger_type(dev->irq) == IRQF_TRIGGER_NONE)  		dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); -	irqflags |= IRQF_SHARED; -  	/* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */  	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */  	mdelay(1); /* delay needs by DM9000B */ @@ -1323,7 +1316,8 @@ dm9000_open(struct net_device *dev)  	/* Initialize DM9000 board */  	dm9000_init_dm9000(dev); -	if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) +	if (request_irq(dev->irq, dm9000_interrupt, IRQF_SHARED, +			dev->name, dev))  		return -EAGAIN;  	/* Now that we have an interrupt handler hooked up we can unmask  	 * our interrupts @@ -1500,15 +1494,22 @@ dm9000_probe(struct platform_device *pdev)  	db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -	db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -	if (db->addr_res == NULL || db->data_res == NULL || -	    db->irq_res == NULL) { -		dev_err(db->dev, "insufficient resources\n"); +	if (!db->addr_res || !db->data_res) { +		dev_err(db->dev, "insufficient resources addr=%p data=%p\n", +			db->addr_res, db->data_res);  		ret = -ENOENT;  		goto out;  	} +	ndev->irq = platform_get_irq(pdev, 0); +	if (ndev->irq < 0) { +		dev_err(db->dev, "interrupt resource unavailable: %d\n", +			ndev->irq); +		ret = ndev->irq; +		goto out; +	} +  	db->irq_wake = platform_get_irq(pdev, 1);  	if (db->irq_wake >= 0) {  		dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake); @@ -1570,7 +1571,6 @@ dm9000_probe(struct platform_device *pdev)  	/* fill in parameters for net-dev structure */  	ndev->base_addr = (unsigned long)db->io_addr; -	ndev->irq	= db->irq_res->start;  	/* ensure at least we have a default set of IO routines */  	dm9000_set_io(db, iosize); diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index cf837831304b..f9751294ece7 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -531,6 +531,7 @@ struct be_adapter {  	struct delayed_work be_err_detection_work;  	u8 err_flags; +	bool pcicfg_mapped;	/* pcicfg obtained via pci_iomap() */  	u32 flags;  	u32 cmd_privileges;  	/* Ethtool knobs and info */ diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 241819b36ca7..6d9a8d78e8ad 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -622,10 +622,13 @@ enum be_if_flags {  					 BE_IF_FLAGS_VLAN_PROMISCUOUS |\  					 BE_IF_FLAGS_MCAST_PROMISCUOUS) -#define BE_IF_EN_FLAGS	(BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |\ -			BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_UNTAGGED) +#define BE_IF_FILT_FLAGS_BASIC (BE_IF_FLAGS_BROADCAST | \ +				BE_IF_FLAGS_PASS_L3L4_ERRORS | \ +				BE_IF_FLAGS_UNTAGGED) -#define BE_IF_ALL_FILT_FLAGS	(BE_IF_EN_FLAGS | BE_IF_FLAGS_ALL_PROMISCUOUS) +#define BE_IF_ALL_FILT_FLAGS	(BE_IF_FILT_FLAGS_BASIC | \ +				 BE_IF_FLAGS_MULTICAST | \ +				 BE_IF_FLAGS_ALL_PROMISCUOUS)  /* An RX interface is an object with one or more MAC addresses and   * filtering capabilities. */ diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index f99de3657ce3..d1cf1274fc2f 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -125,6 +125,11 @@ static const char * const ue_status_hi_desc[] = {  	"Unknown"  }; +#define BE_VF_IF_EN_FLAGS	(BE_IF_FLAGS_UNTAGGED | \ +				 BE_IF_FLAGS_BROADCAST | \ +				 BE_IF_FLAGS_MULTICAST | \ +				 BE_IF_FLAGS_PASS_L3L4_ERRORS) +  static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)  {  	struct be_dma_mem *mem = &q->dma_mem; @@ -3537,7 +3542,7 @@ static int be_enable_if_filters(struct be_adapter *adapter)  {  	int status; -	status = be_cmd_rx_filter(adapter, BE_IF_EN_FLAGS, ON); +	status = be_cmd_rx_filter(adapter, BE_IF_FILT_FLAGS_BASIC, ON);  	if (status)  		return status; @@ -3857,8 +3862,7 @@ static int be_vfs_if_create(struct be_adapter *adapter)  	int status;  	/* If a FW profile exists, then cap_flags are updated */ -	cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | -		    BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS; +	cap_flags = BE_VF_IF_EN_FLAGS;  	for_all_vfs(adapter, vf_cfg, vf) {  		if (!BE3_chip(adapter)) { @@ -3874,10 +3878,8 @@ static int be_vfs_if_create(struct be_adapter *adapter)  			}  		} -		en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED | -					BE_IF_FLAGS_BROADCAST | -					BE_IF_FLAGS_MULTICAST | -					BE_IF_FLAGS_PASS_L3L4_ERRORS); +		/* PF should enable IF flags during proxy if_create call */ +		en_flags = cap_flags & BE_VF_IF_EN_FLAGS;  		status = be_cmd_if_create(adapter, cap_flags, en_flags,  					  &vf_cfg->if_handle, vf + 1);  		if (status) @@ -4968,6 +4970,8 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)  		pci_iounmap(adapter->pdev, adapter->csr);  	if (adapter->db)  		pci_iounmap(adapter->pdev, adapter->db); +	if (adapter->pcicfg && adapter->pcicfg_mapped) +		pci_iounmap(adapter->pdev, adapter->pcicfg);  }  static int db_bar(struct be_adapter *adapter) @@ -5019,8 +5023,10 @@ static int be_map_pci_bars(struct be_adapter *adapter)  			if (!addr)  				goto pci_map_err;  			adapter->pcicfg = addr; +			adapter->pcicfg_mapped = true;  		} else {  			adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET; +			adapter->pcicfg_mapped = false;  		}  	} diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 62fa136554ac..41b010645100 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1265,7 +1265,6 @@ static int ethoc_remove(struct platform_device *pdev)  		if (priv->mdio) {  			mdiobus_unregister(priv->mdio); -			kfree(priv->mdio->irq);  			mdiobus_free(priv->mdio);  		}  		if (priv->clk) diff --git a/drivers/net/ethernet/ezchip/Kconfig b/drivers/net/ethernet/ezchip/Kconfig index 48ecbc8aaaea..b423ad380b6a 100644 --- a/drivers/net/ethernet/ezchip/Kconfig +++ b/drivers/net/ethernet/ezchip/Kconfig @@ -18,6 +18,7 @@ if NET_VENDOR_EZCHIP  config EZCHIP_NPS_MANAGEMENT_ENET  	tristate "EZchip NPS management enet support"  	depends on OF_IRQ && OF_NET +	depends on HAS_IOMEM  	---help---  	  Simple LAN device for debug or management purposes.  	  Device supports interrupts for RX and TX(completion). diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile index 4097c58d17a7..cbe21dc7e37e 100644 --- a/drivers/net/ethernet/freescale/Makefile +++ b/drivers/net/ethernet/freescale/Makefile @@ -4,6 +4,9 @@  obj-$(CONFIG_FEC) += fec.o  fec-objs :=fec_main.o fec_ptp.o +CFLAGS_fec_main.o := -D__CHECK_ENDIAN__ +CFLAGS_fec_ptp.o := -D__CHECK_ENDIAN__ +  obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o  ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)  	obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 99d33e2d35e6..2106d72c91dc 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -19,8 +19,7 @@  #include <linux/timecounter.h>  #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ -    defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ -    defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) +    defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)  /*   *	Just figures, Motorola would have to change the offsets for   *	registers in the same peripheral device on different models @@ -190,28 +189,45 @@  /*   *	Define the buffer descriptor structure. + * + *	Evidently, ARM SoCs have the FEC block generated in a + *	little endian mode so adjust endianness accordingly.   */ -#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) +#if defined(CONFIG_ARM) +#define fec32_to_cpu le32_to_cpu +#define fec16_to_cpu le16_to_cpu +#define cpu_to_fec32 cpu_to_le32 +#define cpu_to_fec16 cpu_to_le16 +#define __fec32 __le32 +#define __fec16 __le16 +  struct bufdesc { -	unsigned short cbd_datlen;	/* Data length */ -	unsigned short cbd_sc;	/* Control and status info */ -	unsigned long cbd_bufaddr;	/* Buffer address */ +	__fec16 cbd_datlen;	/* Data length */ +	__fec16 cbd_sc;		/* Control and status info */ +	__fec32 cbd_bufaddr;	/* Buffer address */  };  #else +#define fec32_to_cpu be32_to_cpu +#define fec16_to_cpu be16_to_cpu +#define cpu_to_fec32 cpu_to_be32 +#define cpu_to_fec16 cpu_to_be16 +#define __fec32 __be32 +#define __fec16 __be16 +  struct bufdesc { -	unsigned short	cbd_sc;			/* Control and status info */ -	unsigned short	cbd_datlen;		/* Data length */ -	unsigned long	cbd_bufaddr;		/* Buffer address */ +	__fec16	cbd_sc;		/* Control and status info */ +	__fec16	cbd_datlen;	/* Data length */ +	__fec32	cbd_bufaddr;	/* Buffer address */  };  #endif  struct bufdesc_ex {  	struct bufdesc desc; -	unsigned long cbd_esc; -	unsigned long cbd_prot; -	unsigned long cbd_bdu; -	unsigned long ts; -	unsigned short res0[4]; +	__fec32 cbd_esc; +	__fec32 cbd_prot; +	__fec32 cbd_bdu; +	__fec32 ts; +	__fec16 res0[4];  };  /* diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 502da6f48f95..41c81f6ec630 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -332,11 +332,13 @@ static void fec_dump(struct net_device *ndev)  	bdp = txq->tx_bd_base;  	do { -		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n", +		pr_info("%3u %c%c 0x%04x 0x%08x %4u %p\n",  			index,  			bdp == txq->cur_tx ? 'S' : ' ',  			bdp == txq->dirty_tx ? 'H' : ' ', -			bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen, +			fec16_to_cpu(bdp->cbd_sc), +			fec32_to_cpu(bdp->cbd_bufaddr), +			fec16_to_cpu(bdp->cbd_datlen),  			txq->tx_skbuff[index]);  		bdp = fec_enet_get_nextdesc(bdp, fep, 0);  		index++; @@ -389,7 +391,7 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,  		bdp = fec_enet_get_nextdesc(bdp, fep, queue);  		ebdp = (struct bufdesc_ex *)bdp; -		status = bdp->cbd_sc; +		status = fec16_to_cpu(bdp->cbd_sc);  		status &= ~BD_ENET_TX_STATS;  		status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);  		frag_len = skb_shinfo(skb)->frags[frag].size; @@ -411,7 +413,7 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,  			if (skb->ip_summed == CHECKSUM_PARTIAL)  				estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;  			ebdp->cbd_bdu = 0; -			ebdp->cbd_esc = estatus; +			ebdp->cbd_esc = cpu_to_fec32(estatus);  		}  		bufaddr = page_address(this_frag->page.p) + this_frag->page_offset; @@ -435,9 +437,9 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,  			goto dma_mapping_error;  		} -		bdp->cbd_bufaddr = addr; -		bdp->cbd_datlen = frag_len; -		bdp->cbd_sc = status; +		bdp->cbd_bufaddr = cpu_to_fec32(addr); +		bdp->cbd_datlen = cpu_to_fec16(frag_len); +		bdp->cbd_sc = cpu_to_fec16(status);  	}  	return bdp; @@ -445,8 +447,8 @@ dma_mapping_error:  	bdp = txq->cur_tx;  	for (i = 0; i < frag; i++) {  		bdp = fec_enet_get_nextdesc(bdp, fep, queue); -		dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, -				bdp->cbd_datlen, DMA_TO_DEVICE); +		dma_unmap_single(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr), +				 fec16_to_cpu(bdp->cbd_datlen), DMA_TO_DEVICE);  	}  	return ERR_PTR(-ENOMEM);  } @@ -483,7 +485,7 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,  	/* Fill in a Tx ring entry */  	bdp = txq->cur_tx;  	last_bdp = bdp; -	status = bdp->cbd_sc; +	status = fec16_to_cpu(bdp->cbd_sc);  	status &= ~BD_ENET_TX_STATS;  	/* Set buffer length and buffer pointer */ @@ -539,21 +541,21 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,  			estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;  		ebdp->cbd_bdu = 0; -		ebdp->cbd_esc = estatus; +		ebdp->cbd_esc = cpu_to_fec32(estatus);  	}  	index = fec_enet_get_bd_index(txq->tx_bd_base, last_bdp, fep);  	/* Save skb pointer */  	txq->tx_skbuff[index] = skb; -	bdp->cbd_datlen = buflen; -	bdp->cbd_bufaddr = addr; +	bdp->cbd_datlen = cpu_to_fec16(buflen); +	bdp->cbd_bufaddr = cpu_to_fec32(addr);  	/* Send it on its way.  Tell FEC it's ready, interrupt when done,  	 * it's the last BD of the frame, and to put the CRC on the end.  	 */  	status |= (BD_ENET_TX_READY | BD_ENET_TX_TC); -	bdp->cbd_sc = status; +	bdp->cbd_sc = cpu_to_fec16(status);  	/* If this was the last BD in the ring, start at the beginning again. */  	bdp = fec_enet_get_nextdesc(last_bdp, fep, queue); @@ -585,7 +587,7 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,  	unsigned int estatus = 0;  	dma_addr_t addr; -	status = bdp->cbd_sc; +	status = fec16_to_cpu(bdp->cbd_sc);  	status &= ~BD_ENET_TX_STATS;  	status |= (BD_ENET_TX_TC | BD_ENET_TX_READY); @@ -607,8 +609,8 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,  		return NETDEV_TX_BUSY;  	} -	bdp->cbd_datlen = size; -	bdp->cbd_bufaddr = addr; +	bdp->cbd_datlen = cpu_to_fec16(size); +	bdp->cbd_bufaddr = cpu_to_fec32(addr);  	if (fep->bufdesc_ex) {  		if (fep->quirks & FEC_QUIRK_HAS_AVB) @@ -616,7 +618,7 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,  		if (skb->ip_summed == CHECKSUM_PARTIAL)  			estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;  		ebdp->cbd_bdu = 0; -		ebdp->cbd_esc = estatus; +		ebdp->cbd_esc = cpu_to_fec32(estatus);  	}  	/* Handle the last BD specially */ @@ -625,10 +627,10 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,  	if (is_last) {  		status |= BD_ENET_TX_INTR;  		if (fep->bufdesc_ex) -			ebdp->cbd_esc |= BD_ENET_TX_INT; +			ebdp->cbd_esc |= cpu_to_fec32(BD_ENET_TX_INT);  	} -	bdp->cbd_sc = status; +	bdp->cbd_sc = cpu_to_fec16(status);  	return 0;  } @@ -647,7 +649,7 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,  	unsigned short status;  	unsigned int estatus = 0; -	status = bdp->cbd_sc; +	status = fec16_to_cpu(bdp->cbd_sc);  	status &= ~BD_ENET_TX_STATS;  	status |= (BD_ENET_TX_TC | BD_ENET_TX_READY); @@ -671,8 +673,8 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,  		}  	} -	bdp->cbd_bufaddr = dmabuf; -	bdp->cbd_datlen = hdr_len; +	bdp->cbd_bufaddr = cpu_to_fec32(dmabuf); +	bdp->cbd_datlen = cpu_to_fec16(hdr_len);  	if (fep->bufdesc_ex) {  		if (fep->quirks & FEC_QUIRK_HAS_AVB) @@ -680,10 +682,10 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,  		if (skb->ip_summed == CHECKSUM_PARTIAL)  			estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;  		ebdp->cbd_bdu = 0; -		ebdp->cbd_esc = estatus; +		ebdp->cbd_esc = cpu_to_fec32(estatus);  	} -	bdp->cbd_sc = status; +	bdp->cbd_sc = cpu_to_fec16(status);  	return 0;  } @@ -823,15 +825,15 @@ static void fec_enet_bd_init(struct net_device *dev)  			/* Initialize the BD for every fragment in the page. */  			if (bdp->cbd_bufaddr) -				bdp->cbd_sc = BD_ENET_RX_EMPTY; +				bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);  			else -				bdp->cbd_sc = 0; +				bdp->cbd_sc = cpu_to_fec16(0);  			bdp = fec_enet_get_nextdesc(bdp, fep, q);  		}  		/* Set the last buffer to wrap */  		bdp = fec_enet_get_prevdesc(bdp, fep, q); -		bdp->cbd_sc |= BD_SC_WRAP; +		bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);  		rxq->cur_rx = rxq->rx_bd_base;  	} @@ -844,18 +846,18 @@ static void fec_enet_bd_init(struct net_device *dev)  		for (i = 0; i < txq->tx_ring_size; i++) {  			/* Initialize the BD for every fragment in the page. */ -			bdp->cbd_sc = 0; +			bdp->cbd_sc = cpu_to_fec16(0);  			if (txq->tx_skbuff[i]) {  				dev_kfree_skb_any(txq->tx_skbuff[i]);  				txq->tx_skbuff[i] = NULL;  			} -			bdp->cbd_bufaddr = 0; +			bdp->cbd_bufaddr = cpu_to_fec32(0);  			bdp = fec_enet_get_nextdesc(bdp, fep, q);  		}  		/* Set the last buffer to wrap */  		bdp = fec_enet_get_prevdesc(bdp, fep, q); -		bdp->cbd_sc |= BD_SC_WRAP; +		bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);  		txq->dirty_tx = bdp;  	}  } @@ -947,8 +949,10 @@ fec_restart(struct net_device *ndev)  	 */  	if (fep->quirks & FEC_QUIRK_ENET_MAC) {  		memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN); -		writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); -		writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); +		writel((__force u32)cpu_to_be32(temp_mac[0]), +		       fep->hwp + FEC_ADDR_LOW); +		writel((__force u32)cpu_to_be32(temp_mac[1]), +		       fep->hwp + FEC_ADDR_HIGH);  	}  	/* Clear any outstanding interrupt. */ @@ -1222,7 +1226,7 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)  	while (bdp != READ_ONCE(txq->cur_tx)) {  		/* Order the load of cur_tx and cbd_sc */  		rmb(); -		status = READ_ONCE(bdp->cbd_sc); +		status = fec16_to_cpu(READ_ONCE(bdp->cbd_sc));  		if (status & BD_ENET_TX_READY)  			break; @@ -1230,10 +1234,12 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)  		skb = txq->tx_skbuff[index];  		txq->tx_skbuff[index] = NULL; -		if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr)) -			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, -					bdp->cbd_datlen, DMA_TO_DEVICE); -		bdp->cbd_bufaddr = 0; +		if (!IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr))) +			dma_unmap_single(&fep->pdev->dev, +					 fec32_to_cpu(bdp->cbd_bufaddr), +					 fec16_to_cpu(bdp->cbd_datlen), +					 DMA_TO_DEVICE); +		bdp->cbd_bufaddr = cpu_to_fec32(0);  		if (!skb) {  			bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);  			continue; @@ -1264,7 +1270,7 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)  			struct skb_shared_hwtstamps shhwtstamps;  			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -			fec_enet_hwtstamp(fep, ebdp->ts, &shhwtstamps); +			fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts), &shhwtstamps);  			skb_tstamp_tx(skb, &shhwtstamps);  		} @@ -1324,10 +1330,8 @@ fec_enet_new_rxbdp(struct net_device *ndev, struct bufdesc *bdp, struct sk_buff  	if (off)  		skb_reserve(skb, fep->rx_align + 1 - off); -	bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, -					  FEC_ENET_RX_FRSIZE - fep->rx_align, -					  DMA_FROM_DEVICE); -	if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { +	bdp->cbd_bufaddr = cpu_to_fec32(dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE - fep->rx_align, DMA_FROM_DEVICE)); +	if (dma_mapping_error(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr))) {  		if (net_ratelimit())  			netdev_err(ndev, "Rx DMA memory map failed\n");  		return -ENOMEM; @@ -1349,7 +1353,8 @@ static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,  	if (!new_skb)  		return false; -	dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr, +	dma_sync_single_for_cpu(&fep->pdev->dev, +				fec32_to_cpu(bdp->cbd_bufaddr),  				FEC_ENET_RX_FRSIZE - fep->rx_align,  				DMA_FROM_DEVICE);  	if (!swap) @@ -1396,7 +1401,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)  	 */  	bdp = rxq->cur_rx; -	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { +	while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY)) {  		if (pkt_received >= budget)  			break; @@ -1438,7 +1443,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)  		/* Process the incoming frame. */  		ndev->stats.rx_packets++; -		pkt_len = bdp->cbd_datlen; +		pkt_len = fec16_to_cpu(bdp->cbd_datlen);  		ndev->stats.rx_bytes += pkt_len;  		index = fec_enet_get_bd_index(rxq->rx_bd_base, bdp, fep); @@ -1456,7 +1461,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)  				ndev->stats.rx_dropped++;  				goto rx_processing_done;  			} -			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, +			dma_unmap_single(&fep->pdev->dev, +					 fec32_to_cpu(bdp->cbd_bufaddr),  					 FEC_ENET_RX_FRSIZE - fep->rx_align,  					 DMA_FROM_DEVICE);  		} @@ -1475,7 +1481,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)  		/* If this is a VLAN packet remove the VLAN Tag */  		vlan_packet_rcvd = false;  		if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) && -			fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) { +		    fep->bufdesc_ex && +		    (ebdp->cbd_esc & cpu_to_fec32(BD_ENET_RX_VLAN))) {  			/* Push and remove the vlan tag */  			struct vlan_hdr *vlan_header =  					(struct vlan_hdr *) (data + ETH_HLEN); @@ -1491,12 +1498,12 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)  		/* Get receive timestamp from the skb */  		if (fep->hwts_rx_en && fep->bufdesc_ex) -			fec_enet_hwtstamp(fep, ebdp->ts, +			fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts),  					  skb_hwtstamps(skb));  		if (fep->bufdesc_ex &&  		    (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { -			if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) { +			if (!(ebdp->cbd_esc & cpu_to_fec32(FLAG_RX_CSUM_ERROR))) {  				/* don't check it */  				skb->ip_summed = CHECKSUM_UNNECESSARY;  			} else { @@ -1513,7 +1520,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)  		napi_gro_receive(&fep->napi, skb);  		if (is_copybreak) { -			dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr, +			dma_sync_single_for_device(&fep->pdev->dev, +						   fec32_to_cpu(bdp->cbd_bufaddr),  						   FEC_ENET_RX_FRSIZE - fep->rx_align,  						   DMA_FROM_DEVICE);  		} else { @@ -1527,12 +1535,12 @@ rx_processing_done:  		/* Mark the buffer empty */  		status |= BD_ENET_RX_EMPTY; -		bdp->cbd_sc = status; +		bdp->cbd_sc = cpu_to_fec16(status);  		if (fep->bufdesc_ex) {  			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -			ebdp->cbd_esc = BD_ENET_RX_INT; +			ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT);  			ebdp->cbd_prot = 0;  			ebdp->cbd_bdu = 0;  		} @@ -2145,8 +2153,7 @@ static int fec_enet_get_regs_len(struct net_device *ndev)  /* List of registers that can be safety be read to dump them with ethtool */  #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ -	defined(CONFIG_M520x) || defined(CONFIG_M532x) ||		\ -	defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) +	defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)  static u32 fec_enet_register_offset[] = {  	FEC_IEVENT, FEC_IMASK, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0,  	FEC_ECNTRL, FEC_MII_DATA, FEC_MII_SPEED, FEC_MIB_CTRLSTAT, FEC_R_CNTRL, @@ -2662,7 +2669,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)  			rxq->rx_skbuff[i] = NULL;  			if (skb) {  				dma_unmap_single(&fep->pdev->dev, -						 bdp->cbd_bufaddr, +						 fec32_to_cpu(bdp->cbd_bufaddr),  						 FEC_ENET_RX_FRSIZE - fep->rx_align,  						 DMA_FROM_DEVICE);  				dev_kfree_skb(skb); @@ -2777,11 +2784,11 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue)  		}  		rxq->rx_skbuff[i] = skb; -		bdp->cbd_sc = BD_ENET_RX_EMPTY; +		bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);  		if (fep->bufdesc_ex) {  			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -			ebdp->cbd_esc = BD_ENET_RX_INT; +			ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT);  		}  		bdp = fec_enet_get_nextdesc(bdp, fep, queue); @@ -2789,7 +2796,7 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue)  	/* Set the last buffer to wrap. */  	bdp = fec_enet_get_prevdesc(bdp, fep, queue); -	bdp->cbd_sc |= BD_SC_WRAP; +	bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);  	return 0;   err_alloc: @@ -2812,12 +2819,12 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue)  		if (!txq->tx_bounce[i])  			goto err_alloc; -		bdp->cbd_sc = 0; -		bdp->cbd_bufaddr = 0; +		bdp->cbd_sc = cpu_to_fec16(0); +		bdp->cbd_bufaddr = cpu_to_fec32(0);  		if (fep->bufdesc_ex) {  			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; -			ebdp->cbd_esc = BD_ENET_TX_INT; +			ebdp->cbd_esc = cpu_to_fec32(BD_ENET_TX_INT);  		}  		bdp = fec_enet_get_nextdesc(bdp, fep, queue); @@ -2825,7 +2832,7 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue)  	/* Set the last buffer to wrap. */  	bdp = fec_enet_get_prevdesc(bdp, fep, queue); -	bdp->cbd_sc |= BD_SC_WRAP; +	bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);  	return 0; diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 623aa1c8ebc6..79a210aaf0bb 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -2791,6 +2791,8 @@ static struct fman *read_dts_node(struct platform_device *of_dev)  		goto fman_free;  	} +	fman->dev = &of_dev->dev; +  	return fman;  fman_node_put: @@ -2845,8 +2847,6 @@ static int fman_probe(struct platform_device *of_dev)  	dev_set_drvdata(dev, fman); -	fman->dev = dev; -  	dev_dbg(dev, "FMan%d probed\n", fman->dts_params.id);  	return 0; diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c index 52e0091b4fb2..1ba359f17ec6 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c @@ -552,7 +552,7 @@ static void tx_restart(struct net_device *dev)  	cbd_t __iomem *prev_bd;  	cbd_t __iomem *last_tx_bd; -	last_tx_bd = fep->tx_bd_base + ((fpi->tx_ring - 1) * sizeof(cbd_t)); +	last_tx_bd = fep->tx_bd_base + (fpi->tx_ring - 1);  	/* get the current bd held in TBPTR  and scan back from this point */  	recheck_bd = curr_tbptr = (cbd_t __iomem *) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 2aa7b401cc3b..f21b2c479780 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1111,8 +1111,10 @@ static void __gfar_detect_errata_85xx(struct gfar_private *priv)  	if ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) == 0x20))  		priv->errata |= GFAR_ERRATA_12; +	/* P2020/P1010 Rev 1; MPC8548 Rev 2 */  	if (((SVR_SOC_VER(svr) == SVR_P2020) && (SVR_REV(svr) < 0x20)) || -	    ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20))) +	    ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)) || +	    ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) < 0x31)))  		priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */  }  #endif @@ -2942,7 +2944,7 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,  	/* change offset to the other half */  	rxb->page_offset ^= GFAR_RXB_TRUESIZE; -	atomic_inc(&page->_count); +	page_ref_inc(page);  	return true;  } diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c index a7139f588ad2..678f5018d0be 100644 --- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c +++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c @@ -469,8 +469,8 @@ static int fmvj18x_config(struct pcmcia_device *link)  		    goto failed;  	    }  	    /* Read MACID from CIS */ -	    for (i = 5; i < 11; i++) -		    dev->dev_addr[i] = buf[i]; +	    for (i = 0; i < 6; i++) +		    dev->dev_addr[i] = buf[i + 5];  	    kfree(buf);  	} else {  	    if (pcmcia_get_mac_from_cis(link, dev)) diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index 74beb1867230..4ccc032633c4 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -25,6 +25,7 @@ config HIX5HD2_GMAC  config HIP04_ETH  	tristate "HISILICON P04 Ethernet support" +	depends on HAS_IOMEM	# For MFD_SYSCON  	select MARVELL_PHY  	select MFD_SYSCON  	select HNS_MDIO diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.c b/drivers/net/ethernet/hisilicon/hns/hnae.c index b3645297477e..3bfe36f9405b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.c +++ b/drivers/net/ethernet/hisilicon/hns/hnae.c @@ -95,21 +95,17 @@ static struct hnae_buf_ops hnae_bops = {  static int __ae_match(struct device *dev, const void *data)  {  	struct hnae_ae_dev *hdev = cls_to_ae_dev(dev); -	const char *ae_id = data; -	if (!strncmp(ae_id, hdev->name, AE_NAME_SIZE)) -		return 1; - -	return 0; +	return hdev->dev->of_node == data;  } -static struct hnae_ae_dev *find_ae(const char *ae_id) +static struct hnae_ae_dev *find_ae(const struct device_node *ae_node)  {  	struct device *dev; -	WARN_ON(!ae_id); +	WARN_ON(!ae_node); -	dev = class_find_device(hnae_class, NULL, ae_id, __ae_match); +	dev = class_find_device(hnae_class, NULL, ae_node, __ae_match);  	return dev ? cls_to_ae_dev(dev) : NULL;  } @@ -316,7 +312,8 @@ EXPORT_SYMBOL(hnae_reinit_handle);   * return handle ptr or ERR_PTR   */  struct hnae_handle *hnae_get_handle(struct device *owner_dev, -				    const char *ae_id, u32 port_id, +				    const struct device_node *ae_node, +				    u32 port_id,  				    struct hnae_buf_ops *bops)  {  	struct hnae_ae_dev *dev; @@ -324,7 +321,7 @@ struct hnae_handle *hnae_get_handle(struct device *owner_dev,  	int i, j;  	int ret; -	dev = find_ae(ae_id); +	dev = find_ae(ae_node);  	if (!dev)  		return ERR_PTR(-ENODEV); diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h index 6ca94dc3dda3..1cbcb9fa3fb5 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.h +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h @@ -524,8 +524,11 @@ struct hnae_handle {  #define ring_to_dev(ring) ((ring)->q->dev->dev) -struct hnae_handle *hnae_get_handle(struct device *owner_dev, const char *ae_id, -				    u32 port_id, struct hnae_buf_ops *bops); +struct hnae_handle *hnae_get_handle(struct device *owner_dev, +				    const struct device_node *ae_node, +				    u32 port_id, +				    struct hnae_buf_ops *bops); +  void hnae_put_handle(struct hnae_handle *handle);  int hnae_ae_register(struct hnae_ae_dev *dev, struct module *owner);  void hnae_ae_unregister(struct hnae_ae_dev *dev); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c index 522b264866b4..d4f92ed322d6 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -675,8 +675,12 @@ static int hns_ae_config_loopback(struct hnae_handle *handle,  {  	int ret;  	struct hnae_vf_cb *vf_cb = hns_ae_get_vf_cb(handle); +	struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle);  	switch (loop) { +	case MAC_INTERNALLOOP_PHY: +		ret = 0; +		break;  	case MAC_INTERNALLOOP_SERDES:  		ret = hns_mac_config_sds_loopback(vf_cb->mac_cb, en);  		break; @@ -686,6 +690,10 @@ static int hns_ae_config_loopback(struct hnae_handle *handle,  	default:  		ret = -EINVAL;  	} + +	if (!ret) +		hns_dsaf_set_inner_lb(mac_cb->dsaf_dev, mac_cb->mac_id, en); +  	return ret;  } @@ -847,6 +855,7 @@ static struct hnae_ae_ops hns_dsaf_ops = {  int hns_dsaf_ae_init(struct dsaf_device *dsaf_dev)  {  	struct hnae_ae_dev *ae_dev = &dsaf_dev->ae_dev; +	static atomic_t id = ATOMIC_INIT(-1);  	switch (dsaf_dev->dsaf_ver) {  	case AE_VERSION_1: @@ -858,6 +867,9 @@ int hns_dsaf_ae_init(struct dsaf_device *dsaf_dev)  	default:  		break;  	} + +	snprintf(ae_dev->name, AE_NAME_SIZE, "%s%d", DSAF_DEVICE_NAME, +		 (int)atomic_inc_return(&id));  	ae_dev->ops = &hns_dsaf_ops;  	ae_dev->dev = dsaf_dev->dev; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 1c33bd06bd5c..38fc5be3870c 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -35,7 +35,7 @@ int hns_dsaf_get_cfg(struct dsaf_device *dsaf_dev)  	int ret, i;  	u32 desc_num;  	u32 buf_size; -	const char *name, *mode_str; +	const char *mode_str;  	struct device_node *np = dsaf_dev->dev->of_node;  	if (of_device_is_compatible(np, "hisilicon,hns-dsaf-v1")) @@ -43,14 +43,6 @@ int hns_dsaf_get_cfg(struct dsaf_device *dsaf_dev)  	else  		dsaf_dev->dsaf_ver = AE_VERSION_2; -	ret = of_property_read_string(np, "dsa_name", &name); -	if (ret) { -		dev_err(dsaf_dev->dev, "get dsaf name fail, ret=%d!\n", ret); -		return ret; -	} -	strncpy(dsaf_dev->ae_dev.name, name, AE_NAME_SIZE); -	dsaf_dev->ae_dev.name[AE_NAME_SIZE - 1] = '\0'; -  	ret = of_property_read_string(np, "mode", &mode_str);  	if (ret) {  		dev_err(dsaf_dev->dev, "get dsaf mode fail, ret=%d!\n", ret); @@ -238,6 +230,30 @@ static void hns_dsaf_mix_def_qid_cfg(struct dsaf_device *dsaf_dev)  	}  } +static void hns_dsaf_inner_qid_cfg(struct dsaf_device *dsaf_dev) +{ +	u16 max_q_per_vf, max_vfn; +	u32 q_id, q_num_per_port; +	u32 mac_id; + +	if (AE_IS_VER1(dsaf_dev->dsaf_ver)) +		return; + +	hns_rcb_get_queue_mode(dsaf_dev->dsaf_mode, +			       HNS_DSAF_COMM_SERVICE_NW_IDX, +			       &max_vfn, &max_q_per_vf); +	q_num_per_port = max_vfn * max_q_per_vf; + +	for (mac_id = 0, q_id = 0; mac_id < DSAF_SERVICE_NW_NUM; mac_id++) { +		dsaf_set_dev_field(dsaf_dev, +				   DSAFV2_SERDES_LBK_0_REG + 4 * mac_id, +				   DSAFV2_SERDES_LBK_QID_M, +				   DSAFV2_SERDES_LBK_QID_S, +				   q_id); +		q_id += q_num_per_port; +	} +} +  /**   * hns_dsaf_sw_port_type_cfg - cfg sw type   * @dsaf_id: dsa fabric id @@ -699,6 +715,16 @@ void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en)  	dsaf_set_dev_bit(dsaf_dev, DSAF_CFG_0_REG, DSAF_CFG_MIX_MODE_S, !!en);  } +void hns_dsaf_set_inner_lb(struct dsaf_device *dsaf_dev, u32 mac_id, u32 en) +{ +	if (AE_IS_VER1(dsaf_dev->dsaf_ver) || +	    dsaf_dev->mac_cb[mac_id].mac_type == HNAE_PORT_DEBUG) +		return; + +	dsaf_set_dev_bit(dsaf_dev, DSAFV2_SERDES_LBK_0_REG + 4 * mac_id, +			 DSAFV2_SERDES_LBK_EN_B, !!en); +} +  /**   * hns_dsaf_tbl_stat_en - tbl   * @dsaf_id: dsa fabric id @@ -1030,6 +1056,9 @@ static void hns_dsaf_comm_init(struct dsaf_device *dsaf_dev)  	/* set promisc def queue id */  	hns_dsaf_mix_def_qid_cfg(dsaf_dev); +	/* set inner loopback queue id */ +	hns_dsaf_inner_qid_cfg(dsaf_dev); +  	/* in non switch mode, set all port to access mode */  	hns_dsaf_sw_port_type_cfg(dsaf_dev, DSAF_SW_PORT_TYPE_NON_VLAN); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h index 31c312f9826e..5fea226efaf3 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h @@ -18,6 +18,7 @@ struct hns_mac_cb;  #define DSAF_DRV_NAME "hns_dsaf"  #define DSAF_MOD_VERSION "v1.0" +#define DSAF_DEVICE_NAME "dsaf"  #define HNS_DSAF_DEBUG_NW_REG_OFFSET 0x100000 @@ -416,5 +417,6 @@ void hns_dsaf_get_strings(int stringset, u8 *data, int port);  void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data);  int hns_dsaf_get_regs_count(void);  void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en); +void hns_dsaf_set_inner_lb(struct dsaf_device *dsaf_dev, u32 mac_id, u32 en);  #endif /* __HNS_DSAF_MAIN_H__ */ diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h index f0c4f9b09d5b..60d695daa471 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h @@ -134,6 +134,7 @@  #define DSAF_XGE_INT_STS_0_REG		0x1C0  #define DSAF_PPE_INT_STS_0_REG		0x1E0  #define DSAF_ROCEE_INT_STS_0_REG	0x200 +#define DSAFV2_SERDES_LBK_0_REG         0x220  #define DSAF_PPE_QID_CFG_0_REG		0x300  #define DSAF_SW_PORT_TYPE_0_REG		0x320  #define DSAF_STP_PORT_TYPE_0_REG	0x340 @@ -857,6 +858,10 @@  #define PPEV2_CFG_RSS_TBL_4N3_S	24  #define PPEV2_CFG_RSS_TBL_4N3_M	(((1UL << 5) - 1) << PPEV2_CFG_RSS_TBL_4N3_S) +#define DSAFV2_SERDES_LBK_EN_B  8 +#define DSAFV2_SERDES_LBK_QID_S 0 +#define DSAFV2_SERDES_LBK_QID_M	(((1UL << 8) - 1) << DSAFV2_SERDES_LBK_QID_S) +  #define PPE_CNT_CLR_CE_B	0  #define PPE_CNT_CLR_SNAP_EN_B	1 diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 0e30846a24f8..3f77ff77abbc 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -1802,7 +1802,7 @@ static int hns_nic_try_get_ae(struct net_device *ndev)  	int ret;  	h = hnae_get_handle(&priv->netdev->dev, -			    priv->ae_name, priv->port_id, NULL); +			    priv->ae_node, priv->port_id, NULL);  	if (IS_ERR_OR_NULL(h)) {  		ret = PTR_ERR(h);  		dev_dbg(priv->dev, "has not handle, register notifier!\n"); @@ -1880,13 +1880,16 @@ static int hns_nic_dev_probe(struct platform_device *pdev)  	else  		priv->enet_ver = AE_VERSION_2; -	ret = of_property_read_string(node, "ae-name", &priv->ae_name); -	if (ret) -		goto out_read_string_fail; +	priv->ae_node = (void *)of_parse_phandle(node, "ae-handle", 0); +	if (IS_ERR_OR_NULL(priv->ae_node)) { +		ret = PTR_ERR(priv->ae_node); +		dev_err(dev, "not find ae-handle\n"); +		goto out_read_prop_fail; +	}  	ret = of_property_read_u32(node, "port-id", &priv->port_id);  	if (ret) -		goto out_read_string_fail; +		goto out_read_prop_fail;  	hns_init_mac_addr(ndev); @@ -1945,7 +1948,7 @@ static int hns_nic_dev_probe(struct platform_device *pdev)  out_notify_fail:  	(void)cancel_work_sync(&priv->service_task); -out_read_string_fail: +out_read_prop_fail:  	free_netdev(ndev);  	return ret;  } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.h b/drivers/net/ethernet/hisilicon/hns/hns_enet.h index 4b75270f014e..c68ab3d34fc2 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.h @@ -51,7 +51,7 @@ struct hns_nic_ops {  };  struct hns_nic_priv { -	const char *ae_name; +	const struct device_node *ae_node;  	u32 enet_ver;  	u32 port_id;  	int phy_mode; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index 3df22840fcd1..3c4a3bc31a89 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -295,8 +295,10 @@ static int __lb_setup(struct net_device *ndev,  	switch (loop) {  	case MAC_INTERNALLOOP_PHY: -		if ((phy_dev) && (!phy_dev->is_c45)) +		if ((phy_dev) && (!phy_dev->is_c45)) {  			ret = hns_nic_config_phy_loopback(phy_dev, 0x1); +			ret |= h->dev->ops->set_loopback(h, loop, 0x1); +		}  		break;  	case MAC_INTERNALLOOP_MAC:  		if ((h->dev->ops->set_loopback) && @@ -376,6 +378,7 @@ static void __lb_other_process(struct hns_nic_ring_data *ring_data,  			       struct sk_buff *skb)  {  	struct net_device *ndev; +	struct hns_nic_priv *priv;  	struct hnae_ring *ring;  	struct netdev_queue *dev_queue;  	struct sk_buff *new_skb; @@ -385,8 +388,17 @@ static void __lb_other_process(struct hns_nic_ring_data *ring_data,  	char buff[33]; /* 32B data and the last character '\0' */  	if (!ring_data) { /* Just for doing create frame*/ +		ndev = skb->dev; +		priv = netdev_priv(ndev); +  		frame_size = skb->len;  		memset(skb->data, 0xFF, frame_size); +		if ((!AE_IS_VER1(priv->enet_ver)) && +		    (priv->ae_handle->port_type == HNAE_PORT_SERVICE)) { +			memcpy(skb->data, ndev->dev_addr, 6); +			skb->data[5] += 0x1f; +		} +  		frame_size &= ~1ul;  		memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);  		memset(&skb->data[frame_size / 2 + 10], 0xBE, @@ -486,6 +498,7 @@ static int __lb_run_test(struct net_device *ndev,  	/* place data into test skb */  	(void)skb_put(skb, size); +	skb->dev = ndev;  	__lb_other_process(NULL, skb);  	skb->queue_mapping = NIC_LB_TEST_RING_ID; diff --git a/drivers/net/ethernet/hp/hp100.c b/drivers/net/ethernet/hp/hp100.c index 1d5c3e16d8f4..3daf2d4a7ca0 100644 --- a/drivers/net/ethernet/hp/hp100.c +++ b/drivers/net/ethernet/hp/hp100.c @@ -194,7 +194,6 @@ static const char *hp100_isa_tbl[] = {  };  #endif -#ifdef CONFIG_EISA  static struct eisa_device_id hp100_eisa_tbl[] = {  	{ "HWPF180" }, /* HP J2577 rev A */  	{ "HWP1920" }, /* HP 27248B */ @@ -205,9 +204,7 @@ static struct eisa_device_id hp100_eisa_tbl[] = {  	{ "" }	       /* Mandatory final entry ! */  };  MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl); -#endif -#ifdef CONFIG_PCI  static const struct pci_device_id hp100_pci_tbl[] = {  	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,},  	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,}, @@ -219,7 +216,6 @@ static const struct pci_device_id hp100_pci_tbl[] = {  	{}			/* Terminating entry */  };  MODULE_DEVICE_TABLE(pci, hp100_pci_tbl); -#endif  static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;  static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; @@ -2842,7 +2838,6 @@ static void cleanup_dev(struct net_device *d)  	free_netdev(d);  } -#ifdef CONFIG_EISA  static int hp100_eisa_probe(struct device *gendev)  {  	struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); @@ -2884,9 +2879,7 @@ static struct eisa_driver hp100_eisa_driver = {  		.remove  = hp100_eisa_remove,          }  }; -#endif -#ifdef CONFIG_PCI  static int hp100_pci_probe(struct pci_dev *pdev,  			   const struct pci_device_id *ent)  { @@ -2955,7 +2948,6 @@ static struct pci_driver hp100_pci_driver = {  	.probe		= hp100_pci_probe,  	.remove		= hp100_pci_remove,  }; -#endif  /*   *  module section @@ -3032,23 +3024,17 @@ static int __init hp100_module_init(void)  	err = hp100_isa_init();  	if (err && err != -ENODEV)  		goto out; -#ifdef CONFIG_EISA  	err = eisa_driver_register(&hp100_eisa_driver);  	if (err && err != -ENODEV)  		goto out2; -#endif -#ifdef CONFIG_PCI  	err = pci_register_driver(&hp100_pci_driver);  	if (err && err != -ENODEV)  		goto out3; -#endif   out:  	return err;   out3: -#ifdef CONFIG_EISA  	eisa_driver_unregister (&hp100_eisa_driver);   out2: -#endif  	hp100_isa_cleanup();  	goto out;  } @@ -3057,12 +3043,8 @@ static int __init hp100_module_init(void)  static void __exit hp100_module_exit(void)  {  	hp100_isa_cleanup(); -#ifdef CONFIG_EISA  	eisa_driver_unregister (&hp100_eisa_driver); -#endif -#ifdef CONFIG_PCI  	pci_unregister_driver (&hp100_pci_driver); -#endif  }  module_init(hp100_module_init) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 335417b4756b..ebe60719e489 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1166,7 +1166,10 @@ map_failed:  	if (!firmware_has_feature(FW_FEATURE_CMO))  		netdev_err(netdev, "tx: unable to map xmit buffer\n");  	adapter->tx_map_failed++; -	skb_linearize(skb); +	if (skb_linearize(skb)) { +		netdev->stats.tx_dropped++; +		goto out; +	}  	force_bounce = 1;  	goto retry_bounce;  } diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 7d6570843723..6e9e16eee5d0 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1348,44 +1348,44 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)  	crq.request_capability.cmd = REQUEST_CAPABILITY;  	crq.request_capability.capability = cpu_to_be16(REQ_TX_QUEUES); -	crq.request_capability.number = cpu_to_be32(adapter->req_tx_queues); +	crq.request_capability.number = cpu_to_be64(adapter->req_tx_queues);  	ibmvnic_send_crq(adapter, &crq);  	crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES); -	crq.request_capability.number = cpu_to_be32(adapter->req_rx_queues); +	crq.request_capability.number = cpu_to_be64(adapter->req_rx_queues);  	ibmvnic_send_crq(adapter, &crq);  	crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES); -	crq.request_capability.number = cpu_to_be32(adapter->req_rx_add_queues); +	crq.request_capability.number = cpu_to_be64(adapter->req_rx_add_queues);  	ibmvnic_send_crq(adapter, &crq);  	crq.request_capability.capability =  	    cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);  	crq.request_capability.number = -	    cpu_to_be32(adapter->req_tx_entries_per_subcrq); +	    cpu_to_be64(adapter->req_tx_entries_per_subcrq);  	ibmvnic_send_crq(adapter, &crq);  	crq.request_capability.capability =  	    cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);  	crq.request_capability.number = -	    cpu_to_be32(adapter->req_rx_add_entries_per_subcrq); +	    cpu_to_be64(adapter->req_rx_add_entries_per_subcrq);  	ibmvnic_send_crq(adapter, &crq);  	crq.request_capability.capability = cpu_to_be16(REQ_MTU); -	crq.request_capability.number = cpu_to_be32(adapter->req_mtu); +	crq.request_capability.number = cpu_to_be64(adapter->req_mtu);  	ibmvnic_send_crq(adapter, &crq);  	if (adapter->netdev->flags & IFF_PROMISC) {  		if (adapter->promisc_supported) {  			crq.request_capability.capability =  			    cpu_to_be16(PROMISC_REQUESTED); -			crq.request_capability.number = cpu_to_be32(1); +			crq.request_capability.number = cpu_to_be64(1);  			ibmvnic_send_crq(adapter, &crq);  		}  	} else {  		crq.request_capability.capability =  		    cpu_to_be16(PROMISC_REQUESTED); -		crq.request_capability.number = cpu_to_be32(0); +		crq.request_capability.number = cpu_to_be64(0);  		ibmvnic_send_crq(adapter, &crq);  	} @@ -2312,93 +2312,93 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,  	switch (be16_to_cpu(crq->query_capability.capability)) {  	case MIN_TX_QUEUES:  		adapter->min_tx_queues = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "min_tx_queues = %lld\n",  			   adapter->min_tx_queues);  		break;  	case MIN_RX_QUEUES:  		adapter->min_rx_queues = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "min_rx_queues = %lld\n",  			   adapter->min_rx_queues);  		break;  	case MIN_RX_ADD_QUEUES:  		adapter->min_rx_add_queues = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "min_rx_add_queues = %lld\n",  			   adapter->min_rx_add_queues);  		break;  	case MAX_TX_QUEUES:  		adapter->max_tx_queues = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "max_tx_queues = %lld\n",  			   adapter->max_tx_queues);  		break;  	case MAX_RX_QUEUES:  		adapter->max_rx_queues = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "max_rx_queues = %lld\n",  			   adapter->max_rx_queues);  		break;  	case MAX_RX_ADD_QUEUES:  		adapter->max_rx_add_queues = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "max_rx_add_queues = %lld\n",  			   adapter->max_rx_add_queues);  		break;  	case MIN_TX_ENTRIES_PER_SUBCRQ:  		adapter->min_tx_entries_per_subcrq = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "min_tx_entries_per_subcrq = %lld\n",  			   adapter->min_tx_entries_per_subcrq);  		break;  	case MIN_RX_ADD_ENTRIES_PER_SUBCRQ:  		adapter->min_rx_add_entries_per_subcrq = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "min_rx_add_entrs_per_subcrq = %lld\n",  			   adapter->min_rx_add_entries_per_subcrq);  		break;  	case MAX_TX_ENTRIES_PER_SUBCRQ:  		adapter->max_tx_entries_per_subcrq = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "max_tx_entries_per_subcrq = %lld\n",  			   adapter->max_tx_entries_per_subcrq);  		break;  	case MAX_RX_ADD_ENTRIES_PER_SUBCRQ:  		adapter->max_rx_add_entries_per_subcrq = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "max_rx_add_entrs_per_subcrq = %lld\n",  			   adapter->max_rx_add_entries_per_subcrq);  		break;  	case TCP_IP_OFFLOAD:  		adapter->tcp_ip_offload = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "tcp_ip_offload = %lld\n",  			   adapter->tcp_ip_offload);  		break;  	case PROMISC_SUPPORTED:  		adapter->promisc_supported = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "promisc_supported = %lld\n",  			   adapter->promisc_supported);  		break;  	case MIN_MTU: -		adapter->min_mtu = be32_to_cpu(crq->query_capability.number); +		adapter->min_mtu = be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "min_mtu = %lld\n", adapter->min_mtu);  		break;  	case MAX_MTU: -		adapter->max_mtu = be32_to_cpu(crq->query_capability.number); +		adapter->max_mtu = be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "max_mtu = %lld\n", adapter->max_mtu);  		break;  	case MAX_MULTICAST_FILTERS:  		adapter->max_multicast_filters = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "max_multicast_filters = %lld\n",  			   adapter->max_multicast_filters);  		break;  	case VLAN_HEADER_INSERTION:  		adapter->vlan_header_insertion = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		if (adapter->vlan_header_insertion)  			netdev->features |= NETIF_F_HW_VLAN_STAG_TX;  		netdev_dbg(netdev, "vlan_header_insertion = %lld\n", @@ -2406,43 +2406,43 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,  		break;  	case MAX_TX_SG_ENTRIES:  		adapter->max_tx_sg_entries = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "max_tx_sg_entries = %lld\n",  			   adapter->max_tx_sg_entries);  		break;  	case RX_SG_SUPPORTED:  		adapter->rx_sg_supported = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "rx_sg_supported = %lld\n",  			   adapter->rx_sg_supported);  		break;  	case OPT_TX_COMP_SUB_QUEUES:  		adapter->opt_tx_comp_sub_queues = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "opt_tx_comp_sub_queues = %lld\n",  			   adapter->opt_tx_comp_sub_queues);  		break;  	case OPT_RX_COMP_QUEUES:  		adapter->opt_rx_comp_queues = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "opt_rx_comp_queues = %lld\n",  			   adapter->opt_rx_comp_queues);  		break;  	case OPT_RX_BUFADD_Q_PER_RX_COMP_Q:  		adapter->opt_rx_bufadd_q_per_rx_comp_q = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "opt_rx_bufadd_q_per_rx_comp_q = %lld\n",  			   adapter->opt_rx_bufadd_q_per_rx_comp_q);  		break;  	case OPT_TX_ENTRIES_PER_SUBCRQ:  		adapter->opt_tx_entries_per_subcrq = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "opt_tx_entries_per_subcrq = %lld\n",  			   adapter->opt_tx_entries_per_subcrq);  		break;  	case OPT_RXBA_ENTRIES_PER_SUBCRQ:  		adapter->opt_rxba_entries_per_subcrq = -		    be32_to_cpu(crq->query_capability.number); +		    be64_to_cpu(crq->query_capability.number);  		netdev_dbg(netdev, "opt_rxba_entries_per_subcrq = %lld\n",  			   adapter->opt_rxba_entries_per_subcrq);  		break; diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 1242925ad34c..1a9993cc79b5 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -319,10 +319,8 @@ struct ibmvnic_capability {  	u8 first;  	u8 cmd;  	__be16 capability; /* one of ibmvnic_capabilities */ +	__be64 number;  	struct ibmvnic_rc rc; -	__be32 number; /*FIX: should be __be64, but I'm getting the least -			* significant word first -			*/  } __packed __aligned(8);  struct ibmvnic_login { diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index fa593dd3efe1..3772f3ac956e 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -83,6 +83,15 @@ config E1000E  	  To compile this driver as a module, choose M here. The module  	  will be called e1000e. +config E1000E_HWTS +	bool "Support HW cross-timestamp on PCH devices" +	default y +	depends on E1000E && X86 +	---help--- +	 Say Y to enable hardware supported cross-timestamping on PCH +	 devices. The cross-timestamp is available through the PTP clock +	 driver precise cross-timestamp ioctl (PTP_SYS_OFFSET_PRECISE). +  config IGB  	tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"  	depends on PCI diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index f7c7804d79e5..0641c0098738 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -528,6 +528,11 @@  #define E1000_RXCW_C          0x20000000        /* Receive config */  #define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */ +/* HH Time Sync */ +#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK	0x0000F000 /* max delay */ +#define E1000_TSYNCTXCTL_SYNC_COMP		0x40000000 /* sync complete */ +#define E1000_TSYNCTXCTL_START_SYNC		0x80000000 /* initiate sync */ +  #define E1000_TSYNCTXCTL_VALID		0x00000001 /* Tx timestamp valid */  #define E1000_TSYNCTXCTL_ENABLED	0x00000010 /* enable Tx timestamping */ diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index 25a0ad5102d6..e2ff3ef75d5d 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -26,6 +26,12 @@  #include "e1000.h" +#ifdef CONFIG_E1000E_HWTS +#include <linux/clocksource.h> +#include <linux/ktime.h> +#include <asm/tsc.h> +#endif +  /**   * e1000e_phc_adjfreq - adjust the frequency of the hardware clock   * @ptp: ptp clock structure @@ -98,6 +104,78 @@ static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)  	return 0;  } +#ifdef CONFIG_E1000E_HWTS +#define MAX_HW_WAIT_COUNT (3) + +/** + * e1000e_phc_get_syncdevicetime - Callback given to timekeeping code reads system/device registers + * @device: current device time + * @system: system counter value read synchronously with device time + * @ctx: context provided by timekeeping code + * + * Read device and system (ART) clock simultaneously and return the corrected + * clock values in ns. + **/ +static int e1000e_phc_get_syncdevicetime(ktime_t *device, +					 struct system_counterval_t *system, +					 void *ctx) +{ +	struct e1000_adapter *adapter = (struct e1000_adapter *)ctx; +	struct e1000_hw *hw = &adapter->hw; +	unsigned long flags; +	int i; +	u32 tsync_ctrl; +	cycle_t dev_cycles; +	cycle_t sys_cycles; + +	tsync_ctrl = er32(TSYNCTXCTL); +	tsync_ctrl |= E1000_TSYNCTXCTL_START_SYNC | +		E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK; +	ew32(TSYNCTXCTL, tsync_ctrl); +	for (i = 0; i < MAX_HW_WAIT_COUNT; ++i) { +		udelay(1); +		tsync_ctrl = er32(TSYNCTXCTL); +		if (tsync_ctrl & E1000_TSYNCTXCTL_SYNC_COMP) +			break; +	} + +	if (i == MAX_HW_WAIT_COUNT) +		return -ETIMEDOUT; + +	dev_cycles = er32(SYSSTMPH); +	dev_cycles <<= 32; +	dev_cycles |= er32(SYSSTMPL); +	spin_lock_irqsave(&adapter->systim_lock, flags); +	*device = ns_to_ktime(timecounter_cyc2time(&adapter->tc, dev_cycles)); +	spin_unlock_irqrestore(&adapter->systim_lock, flags); + +	sys_cycles = er32(PLTSTMPH); +	sys_cycles <<= 32; +	sys_cycles |= er32(PLTSTMPL); +	*system = convert_art_to_tsc(sys_cycles); + +	return 0; +} + +/** + * e1000e_phc_getsynctime - Reads the current system/device cross timestamp + * @ptp: ptp clock structure + * @cts: structure containing timestamp + * + * Read device and system (ART) clock simultaneously and return the scaled + * clock values in ns. + **/ +static int e1000e_phc_getcrosststamp(struct ptp_clock_info *ptp, +				     struct system_device_crosststamp *xtstamp) +{ +	struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter, +						     ptp_clock_info); + +	return get_device_system_crosststamp(e1000e_phc_get_syncdevicetime, +						adapter, NULL, xtstamp); +} +#endif/*CONFIG_E1000E_HWTS*/ +  /**   * e1000e_phc_gettime - Reads the current time from the hardware clock   * @ptp: ptp clock structure @@ -236,6 +314,13 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)  		break;  	} +#ifdef CONFIG_E1000E_HWTS +	/* CPU must have ART and GBe must be from Sunrise Point or greater */ +	if (hw->mac.type >= e1000_pch_spt && boot_cpu_has(X86_FEATURE_ART)) +		adapter->ptp_clock_info.getcrosststamp = +			e1000e_phc_getcrosststamp; +#endif/*CONFIG_E1000E_HWTS*/ +  	INIT_DELAYED_WORK(&adapter->systim_overflow_work,  			  e1000e_systim_overflow_work); diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index 1d5e0b77062a..0cb4d365e5ad 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -245,6 +245,10 @@  #define E1000_SYSTIML	0x0B600	/* System time register Low - RO */  #define E1000_SYSTIMH	0x0B604	/* System time register High - RO */  #define E1000_TIMINCA	0x0B608	/* Increment attributes register - RW */ +#define E1000_SYSSTMPL  0x0B648 /* HH Timesync system stamp low register */ +#define E1000_SYSSTMPH  0x0B64C /* HH Timesync system stamp hi register */ +#define E1000_PLTSTMPL  0x0B640 /* HH Timesync platform stamp low register */ +#define E1000_PLTSTMPH  0x0B644 /* HH Timesync platform stamp hi register */  #define E1000_RXMTRL	0x0B634	/* Time sync Rx EtherType and Msg Type - RW */  #define E1000_RXUDP	0x0B638	/* Time Sync Rx UDP Port - RW */ diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index b243c3cbe68f..b4547ebed774 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -243,7 +243,7 @@ static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer,  	/* Even if we own the page, we are not allowed to use atomic_set()  	 * This would break get_page_unless_zero() users.  	 */ -	atomic_inc(&page->_count); +	page_ref_inc(page);  	return true;  } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index bb4612c159fd..8f3b53e0dc46 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7117,9 +7117,7 @@ static void i40e_service_task(struct work_struct *work)  	i40e_watchdog_subtask(pf);  	i40e_fdir_reinit_subtask(pf);  	i40e_sync_filters_subtask(pf); -#if IS_ENABLED(CONFIG_VXLAN) || IS_ENABLED(CONFIG_GENEVE)  	i40e_sync_udp_filters_subtask(pf); -#endif  	i40e_clean_adminq_subtask(pf);  	i40e_service_event_complete(pf); @@ -8515,6 +8513,8 @@ static u8 i40e_get_udp_port_idx(struct i40e_pf *pf, __be16 port)  }  #endif + +#if IS_ENABLED(CONFIG_VXLAN)  /**   * i40e_add_vxlan_port - Get notifications about VXLAN ports that come up   * @netdev: This physical port's netdev @@ -8524,7 +8524,6 @@ static u8 i40e_get_udp_port_idx(struct i40e_pf *pf, __be16 port)  static void i40e_add_vxlan_port(struct net_device *netdev,  				sa_family_t sa_family, __be16 port)  { -#if IS_ENABLED(CONFIG_VXLAN)  	struct i40e_netdev_priv *np = netdev_priv(netdev);  	struct i40e_vsi *vsi = np->vsi;  	struct i40e_pf *pf = vsi->back; @@ -8557,7 +8556,6 @@ static void i40e_add_vxlan_port(struct net_device *netdev,  	pf->udp_ports[next_idx].type = I40E_AQC_TUNNEL_TYPE_VXLAN;  	pf->pending_udp_bitmap |= BIT_ULL(next_idx);  	pf->flags |= I40E_FLAG_UDP_FILTER_SYNC; -#endif  }  /** @@ -8569,7 +8567,6 @@ static void i40e_add_vxlan_port(struct net_device *netdev,  static void i40e_del_vxlan_port(struct net_device *netdev,  				sa_family_t sa_family, __be16 port)  { -#if IS_ENABLED(CONFIG_VXLAN)  	struct i40e_netdev_priv *np = netdev_priv(netdev);  	struct i40e_vsi *vsi = np->vsi;  	struct i40e_pf *pf = vsi->back; @@ -8592,9 +8589,10 @@ static void i40e_del_vxlan_port(struct net_device *netdev,  		netdev_warn(netdev, "vxlan port %d was not found, not deleting\n",  			    ntohs(port));  	} -#endif  } +#endif +#if IS_ENABLED(CONFIG_GENEVE)  /**   * i40e_add_geneve_port - Get notifications about GENEVE ports that come up   * @netdev: This physical port's netdev @@ -8604,7 +8602,6 @@ static void i40e_del_vxlan_port(struct net_device *netdev,  static void i40e_add_geneve_port(struct net_device *netdev,  				 sa_family_t sa_family, __be16 port)  { -#if IS_ENABLED(CONFIG_GENEVE)  	struct i40e_netdev_priv *np = netdev_priv(netdev);  	struct i40e_vsi *vsi = np->vsi;  	struct i40e_pf *pf = vsi->back; @@ -8639,7 +8636,6 @@ static void i40e_add_geneve_port(struct net_device *netdev,  	pf->flags |= I40E_FLAG_UDP_FILTER_SYNC;  	dev_info(&pf->pdev->dev, "adding geneve port %d\n", ntohs(port)); -#endif  }  /** @@ -8651,7 +8647,6 @@ static void i40e_add_geneve_port(struct net_device *netdev,  static void i40e_del_geneve_port(struct net_device *netdev,  				 sa_family_t sa_family, __be16 port)  { -#if IS_ENABLED(CONFIG_GENEVE)  	struct i40e_netdev_priv *np = netdev_priv(netdev);  	struct i40e_vsi *vsi = np->vsi;  	struct i40e_pf *pf = vsi->back; @@ -8677,8 +8672,8 @@ static void i40e_del_geneve_port(struct net_device *netdev,  		netdev_warn(netdev, "geneve port %d was not found, not deleting\n",  			    ntohs(port));  	} -#endif  } +#endif  static int i40e_get_phys_port_id(struct net_device *netdev,  				 struct netdev_phys_item_id *ppid) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 720516b0e8ee..47bd8b3145a7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2313,8 +2313,8 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,  	struct iphdr *this_ip_hdr;  	u32 network_hdr_len;  	u8 l4_hdr = 0; -	struct udphdr *oudph; -	struct iphdr *oiph; +	struct udphdr *oudph = NULL; +	struct iphdr *oiph = NULL;  	u32 l4_tunnel = 0;  	if (skb->encapsulation) { diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 31e5f3942839..5b4ad1ad4d5f 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6630,7 +6630,7 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,  	/* Even if we own the page, we are not allowed to use atomic_set()  	 * This would break get_page_unless_zero() users.  	 */ -	atomic_inc(&page->_count); +	page_ref_inc(page);  	return true;  } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index c4003a88bbf6..e6035ff6b861 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1942,7 +1942,7 @@ static bool ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,  	/* Even if we own the page, we are not allowed to use atomic_set()  	 * This would break get_page_unless_zero() users.  	 */ -	atomic_inc(&page->_count); +	page_ref_inc(page);  	return true;  } diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 3558f019b631..0ea14c0a2e74 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -837,7 +837,7 @@ add_tail_frag:  	/* Even if we own the page, we are not allowed to use atomic_set()  	 * This would break get_page_unless_zero() users.  	 */ -	atomic_inc(&page->_count); +	page_ref_inc(page);  	return true;  } diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index b1de7afd4116..3ddf657bc10b 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -270,11 +270,17 @@ jme_reset_mac_processor(struct jme_adapter *jme)  }  static inline void -jme_clear_pm(struct jme_adapter *jme) +jme_clear_pm_enable_wol(struct jme_adapter *jme)  {  	jwrite32(jme, JME_PMCS, PMCS_STMASK | jme->reg_pmcs);  } +static inline void +jme_clear_pm_disable_wol(struct jme_adapter *jme) +{ +	jwrite32(jme, JME_PMCS, PMCS_STMASK); +} +  static int  jme_reload_eeprom(struct jme_adapter *jme)  { @@ -1853,7 +1859,7 @@ jme_open(struct net_device *netdev)  	struct jme_adapter *jme = netdev_priv(netdev);  	int rc; -	jme_clear_pm(jme); +	jme_clear_pm_disable_wol(jme);  	JME_NAPI_ENABLE(jme);  	tasklet_init(&jme->linkch_task, jme_link_change_tasklet, @@ -1925,11 +1931,11 @@ jme_wait_link(struct jme_adapter *jme)  static void  jme_powersave_phy(struct jme_adapter *jme)  { -	if (jme->reg_pmcs) { +	if (jme->reg_pmcs && device_may_wakeup(&jme->pdev->dev)) {  		jme_set_100m_half(jme);  		if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))  			jme_wait_link(jme); -		jme_clear_pm(jme); +		jme_clear_pm_enable_wol(jme);  	} else {  		jme_phy_off(jme);  	} @@ -2646,9 +2652,6 @@ jme_set_wol(struct net_device *netdev,  	if (wol->wolopts & WAKE_MAGIC)  		jme->reg_pmcs |= PMCS_MFEN; -	jwrite32(jme, JME_PMCS, jme->reg_pmcs); -	device_set_wakeup_enable(&jme->pdev->dev, !!(jme->reg_pmcs)); -  	return 0;  } @@ -3172,8 +3175,8 @@ jme_init_one(struct pci_dev *pdev,  	jme->mii_if.mdio_read = jme_mdio_read;  	jme->mii_if.mdio_write = jme_mdio_write; -	jme_clear_pm(jme); -	device_set_wakeup_enable(&pdev->dev, true); +	jme_clear_pm_disable_wol(jme); +	device_init_wakeup(&pdev->dev, true);  	jme_set_phyfifo_5level(jme);  	jme->pcirev = pdev->revision; @@ -3304,7 +3307,7 @@ jme_resume(struct device *dev)  	if (!netif_running(netdev))  		return 0; -	jme_clear_pm(jme); +	jme_clear_pm_disable_wol(jme);  	jme_phy_on(jme);  	if (test_bit(JME_FLAG_SSET, &jme->flags))  		jme_set_settings(netdev, &jme->old_ecmd); @@ -3312,13 +3315,14 @@ jme_resume(struct device *dev)  		jme_reset_phy_processor(jme);  	jme_phy_calibration(jme);  	jme_phy_setEA(jme); -	jme_start_irq(jme);  	netif_device_attach(netdev);  	atomic_inc(&jme->link_changing);  	jme_reset_link(jme); +	jme_start_irq(jme); +  	return 0;  } diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index a0c03834a2f7..55831188bc32 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -762,10 +762,10 @@ txq_put_data_tso(struct net_device *dev, struct tx_queue *txq,  	if (length <= 8 && (uintptr_t)data & 0x7) {  		/* Copy unaligned small data fragment to TSO header data area */ -		memcpy(txq->tso_hdrs + txq->tx_curr_desc * TSO_HEADER_SIZE, +		memcpy(txq->tso_hdrs + tx_index * TSO_HEADER_SIZE,  		       data, length);  		desc->buf_ptr = txq->tso_hdrs_dma -			+ txq->tx_curr_desc * TSO_HEADER_SIZE; +			+ tx_index * TSO_HEADER_SIZE;  	} else {  		/* Alignment is okay, map buffer and hand off to hardware */  		txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index fabc8df40392..b0ae69f84493 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -11,28 +11,28 @@   * warranty of any kind, whether express or implied.   */ -#include <linux/kernel.h> -#include <linux/netdevice.h> +#include <linux/clk.h> +#include <linux/cpu.h>  #include <linux/etherdevice.h> -#include <linux/platform_device.h> -#include <linux/skbuff.h> +#include <linux/if_vlan.h>  #include <linux/inetdevice.h> -#include <linux/mbus.h> -#include <linux/module.h>  #include <linux/interrupt.h> -#include <linux/if_vlan.h> -#include <net/ip.h> -#include <net/ipv6.h>  #include <linux/io.h> -#include <net/tso.h> +#include <linux/kernel.h> +#include <linux/mbus.h> +#include <linux/module.h> +#include <linux/netdevice.h>  #include <linux/of.h> +#include <linux/of_address.h>  #include <linux/of_irq.h>  #include <linux/of_mdio.h>  #include <linux/of_net.h> -#include <linux/of_address.h>  #include <linux/phy.h> -#include <linux/clk.h> -#include <linux/cpu.h> +#include <linux/platform_device.h> +#include <linux/skbuff.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <net/tso.h>  /* Registers */  #define MVNETA_RXQ_CONFIG_REG(q)                (0x1400 + ((q) << 2)) @@ -370,9 +370,16 @@ struct mvneta_port {  	struct net_device *dev;  	struct notifier_block cpu_notifier;  	int rxq_def; +	/* Protect the access to the percpu interrupt registers, +	 * ensuring that the configuration remains coherent. +	 */ +	spinlock_t lock; +	bool is_stopped;  	/* Core clock */  	struct clk *clk; +	/* AXI clock */ +	struct clk *clk_bus;  	u8 mcast_count[256];  	u16 tx_ring_size;  	u16 rx_ring_size; @@ -1036,6 +1043,43 @@ static void mvneta_set_autoneg(struct mvneta_port *pp, int enable)  	}  } +static void mvneta_percpu_unmask_interrupt(void *arg) +{ +	struct mvneta_port *pp = arg; + +	/* All the queue are unmasked, but actually only the ones +	 * mapped to this CPU will be unmasked +	 */ +	mvreg_write(pp, MVNETA_INTR_NEW_MASK, +		    MVNETA_RX_INTR_MASK_ALL | +		    MVNETA_TX_INTR_MASK_ALL | +		    MVNETA_MISCINTR_INTR_MASK); +} + +static void mvneta_percpu_mask_interrupt(void *arg) +{ +	struct mvneta_port *pp = arg; + +	/* All the queue are masked, but actually only the ones +	 * mapped to this CPU will be masked +	 */ +	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); +	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); +	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); +} + +static void mvneta_percpu_clear_intr_cause(void *arg) +{ +	struct mvneta_port *pp = arg; + +	/* All the queue are cleared, but actually only the ones +	 * mapped to this CPU will be cleared +	 */ +	mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0); +	mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); +	mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); +} +  /* This method sets defaults to the NETA port:   *	Clears interrupt Cause and Mask registers.   *	Clears all MAC tables. @@ -1053,14 +1097,10 @@ static void mvneta_defaults_set(struct mvneta_port *pp)  	int max_cpu = num_present_cpus();  	/* Clear all Cause registers */ -	mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0); -	mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); -	mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); +	on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);  	/* Mask all interrupts */ -	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); -	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); -	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); +	on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);  	mvreg_write(pp, MVNETA_INTR_ENABLE, 0);  	/* Enable MBUS Retry bit16 */ @@ -2526,34 +2566,9 @@ static int mvneta_setup_txqs(struct mvneta_port *pp)  	return 0;  } -static void mvneta_percpu_unmask_interrupt(void *arg) -{ -	struct mvneta_port *pp = arg; - -	/* All the queue are unmasked, but actually only the ones -	 * maped to this CPU will be unmasked -	 */ -	mvreg_write(pp, MVNETA_INTR_NEW_MASK, -		    MVNETA_RX_INTR_MASK_ALL | -		    MVNETA_TX_INTR_MASK_ALL | -		    MVNETA_MISCINTR_INTR_MASK); -} - -static void mvneta_percpu_mask_interrupt(void *arg) -{ -	struct mvneta_port *pp = arg; - -	/* All the queue are masked, but actually only the ones -	 * maped to this CPU will be masked -	 */ -	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); -	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); -	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); -} -  static void mvneta_start_dev(struct mvneta_port *pp)  { -	unsigned int cpu; +	int cpu;  	mvneta_max_rx_size_set(pp, pp->pkt_size);  	mvneta_txq_max_tx_size_set(pp, pp->pkt_size); @@ -2562,16 +2577,15 @@ static void mvneta_start_dev(struct mvneta_port *pp)  	mvneta_port_enable(pp);  	/* Enable polling on the port */ -	for_each_present_cpu(cpu) { +	for_each_online_cpu(cpu) {  		struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);  		napi_enable(&port->napi);  	}  	/* Unmask interrupts. It has to be done from each CPU */ -	for_each_online_cpu(cpu) -		smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt, -					 pp, true); +	on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true); +  	mvreg_write(pp, MVNETA_INTR_MISC_MASK,  		    MVNETA_CAUSE_PHY_STATUS_CHANGE |  		    MVNETA_CAUSE_LINK_CHANGE | @@ -2587,7 +2601,7 @@ static void mvneta_stop_dev(struct mvneta_port *pp)  	phy_stop(pp->phy_dev); -	for_each_present_cpu(cpu) { +	for_each_online_cpu(cpu) {  		struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);  		napi_disable(&port->napi); @@ -2602,13 +2616,10 @@ static void mvneta_stop_dev(struct mvneta_port *pp)  	mvneta_port_disable(pp);  	/* Clear all ethernet port interrupts */ -	mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); -	mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); +	on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);  	/* Mask all ethernet port interrupts */ -	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); -	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); -	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); +	on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);  	mvneta_tx_reset(pp);  	mvneta_rx_reset(pp); @@ -2845,11 +2856,20 @@ static void mvneta_percpu_disable(void *arg)  	disable_percpu_irq(pp->dev->irq);  } +/* Electing a CPU must be done in an atomic way: it should be done + * after or before the removal/insertion of a CPU and this function is + * not reentrant. + */  static void mvneta_percpu_elect(struct mvneta_port *pp)  { -	int online_cpu_idx, max_cpu, cpu, i = 0; +	int elected_cpu = 0, max_cpu, cpu, i = 0; + +	/* Use the cpu associated to the rxq when it is online, in all +	 * the other cases, use the cpu 0 which can't be offline. +	 */ +	if (cpu_online(pp->rxq_def)) +		elected_cpu = pp->rxq_def; -	online_cpu_idx = pp->rxq_def % num_online_cpus();  	max_cpu = num_present_cpus();  	for_each_online_cpu(cpu) { @@ -2860,7 +2880,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp)  			if ((rxq % max_cpu) == cpu)  				rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq); -		if (i == online_cpu_idx) +		if (cpu == elected_cpu)  			/* Map the default receive queue queue to the  			 * elected CPU  			 */ @@ -2871,7 +2891,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp)  		 * the CPU bound to the default RX queue  		 */  		if (txq_number == 1) -			txq_map = (i == online_cpu_idx) ? +			txq_map = (cpu == elected_cpu) ?  				MVNETA_CPU_TXQ_ACCESS(1) : 0;  		else  			txq_map = mvreg_read(pp, MVNETA_CPU_MAP(cpu)) & @@ -2900,6 +2920,14 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,  	switch (action) {  	case CPU_ONLINE:  	case CPU_ONLINE_FROZEN: +		spin_lock(&pp->lock); +		/* Configuring the driver for a new CPU while the +		 * driver is stopping is racy, so just avoid it. +		 */ +		if (pp->is_stopped) { +			spin_unlock(&pp->lock); +			break; +		}  		netif_tx_stop_all_queues(pp->dev);  		/* We have to synchronise on tha napi of each CPU @@ -2915,9 +2943,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,  		}  		/* Mask all ethernet port interrupts */ -		mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); -		mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); -		mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); +		on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);  		napi_enable(&port->napi); @@ -2932,27 +2958,25 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,  		 */  		mvneta_percpu_elect(pp); -		/* Unmask all ethernet port interrupts, as this -		 * notifier is called for each CPU then the CPU to -		 * Queue mapping is applied -		 */ -		mvreg_write(pp, MVNETA_INTR_NEW_MASK, -			MVNETA_RX_INTR_MASK(rxq_number) | -			MVNETA_TX_INTR_MASK(txq_number) | -			MVNETA_MISCINTR_INTR_MASK); +		/* Unmask all ethernet port interrupts */ +		on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);  		mvreg_write(pp, MVNETA_INTR_MISC_MASK,  			MVNETA_CAUSE_PHY_STATUS_CHANGE |  			MVNETA_CAUSE_LINK_CHANGE |  			MVNETA_CAUSE_PSC_SYNC_CHANGE);  		netif_tx_start_all_queues(pp->dev); +		spin_unlock(&pp->lock);  		break;  	case CPU_DOWN_PREPARE:  	case CPU_DOWN_PREPARE_FROZEN:  		netif_tx_stop_all_queues(pp->dev); +		/* Thanks to this lock we are sure that any pending +		 * cpu election is done +		 */ +		spin_lock(&pp->lock);  		/* Mask all ethernet port interrupts */ -		mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); -		mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); -		mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); +		on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); +		spin_unlock(&pp->lock);  		napi_synchronize(&port->napi);  		napi_disable(&port->napi); @@ -2966,12 +2990,11 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,  	case CPU_DEAD:  	case CPU_DEAD_FROZEN:  		/* Check if a new CPU must be elected now this on is down */ +		spin_lock(&pp->lock);  		mvneta_percpu_elect(pp); +		spin_unlock(&pp->lock);  		/* Unmask all ethernet port interrupts */ -		mvreg_write(pp, MVNETA_INTR_NEW_MASK, -			MVNETA_RX_INTR_MASK(rxq_number) | -			MVNETA_TX_INTR_MASK(txq_number) | -			MVNETA_MISCINTR_INTR_MASK); +		on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);  		mvreg_write(pp, MVNETA_INTR_MISC_MASK,  			MVNETA_CAUSE_PHY_STATUS_CHANGE |  			MVNETA_CAUSE_LINK_CHANGE | @@ -2986,7 +3009,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,  static int mvneta_open(struct net_device *dev)  {  	struct mvneta_port *pp = netdev_priv(dev); -	int ret, cpu; +	int ret;  	pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu);  	pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) + @@ -3008,22 +3031,12 @@ static int mvneta_open(struct net_device *dev)  		goto err_cleanup_txqs;  	} -	/* Even though the documentation says that request_percpu_irq -	 * doesn't enable the interrupts automatically, it actually -	 * does so on the local CPU. -	 * -	 * Make sure it's disabled. -	 */ -	mvneta_percpu_disable(pp); -  	/* Enable per-CPU interrupt on all the CPU to handle our RX  	 * queue interrupts  	 */ -	for_each_online_cpu(cpu) -		smp_call_function_single(cpu, mvneta_percpu_enable, -					 pp, true); - +	on_each_cpu(mvneta_percpu_enable, pp, true); +	pp->is_stopped = false;  	/* Register a CPU notifier to handle the case where our CPU  	 * might be taken offline.  	 */ @@ -3055,13 +3068,20 @@ err_cleanup_rxqs:  static int mvneta_stop(struct net_device *dev)  {  	struct mvneta_port *pp = netdev_priv(dev); -	int cpu; +	/* Inform that we are stopping so we don't want to setup the +	 * driver for new CPUs in the notifiers +	 */ +	spin_lock(&pp->lock); +	pp->is_stopped = true;  	mvneta_stop_dev(pp);  	mvneta_mdio_remove(pp);  	unregister_cpu_notifier(&pp->cpu_notifier); -	for_each_present_cpu(cpu) -		smp_call_function_single(cpu, mvneta_percpu_disable, pp, true); +	/* Now that the notifier are unregistered, we can release le +	 * lock +	 */ +	spin_unlock(&pp->lock); +	on_each_cpu(mvneta_percpu_disable, pp, true);  	free_percpu_irq(dev->irq, pp->ports);  	mvneta_cleanup_rxqs(pp);  	mvneta_cleanup_txqs(pp); @@ -3242,26 +3262,25 @@ static void mvneta_ethtool_update_stats(struct mvneta_port *pp)  	const struct mvneta_statistic *s;  	void __iomem *base = pp->base;  	u32 high, low, val; +	u64 val64;  	int i;  	for (i = 0, s = mvneta_statistics;  	     s < mvneta_statistics + ARRAY_SIZE(mvneta_statistics);  	     s++, i++) { -		val = 0; -  		switch (s->type) {  		case T_REG_32:  			val = readl_relaxed(base + s->offset); +			pp->ethtool_stats[i] += val;  			break;  		case T_REG_64:  			/* Docs say to read low 32-bit then high */  			low = readl_relaxed(base + s->offset);  			high = readl_relaxed(base + s->offset + 4); -			val = (u64)high << 32 | low; +			val64 = (u64)high << 32 | low; +			pp->ethtool_stats[i] += val64;  			break;  		} - -		pp->ethtool_stats[i] += val;  	}  } @@ -3311,9 +3330,7 @@ static int  mvneta_config_rss(struct mvneta_port *pp)  	netif_tx_stop_all_queues(pp->dev); -	for_each_online_cpu(cpu) -		smp_call_function_single(cpu, mvneta_percpu_mask_interrupt, -					 pp, true); +	on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);  	/* We have to synchronise on the napi of each CPU */  	for_each_online_cpu(cpu) { @@ -3334,7 +3351,9 @@ static int  mvneta_config_rss(struct mvneta_port *pp)  	mvreg_write(pp, MVNETA_PORT_CONFIG, val);  	/* Update the elected CPU matching the new rxq_def */ +	spin_lock(&pp->lock);  	mvneta_percpu_elect(pp); +	spin_unlock(&pp->lock);  	/* We have to synchronise on the napi of each CPU */  	for_each_online_cpu(cpu) { @@ -3605,7 +3624,9 @@ static int mvneta_probe(struct platform_device *pdev)  	pp->indir[0] = rxq_def; -	pp->clk = devm_clk_get(&pdev->dev, NULL); +	pp->clk = devm_clk_get(&pdev->dev, "core"); +	if (IS_ERR(pp->clk)) +		pp->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(pp->clk)) {  		err = PTR_ERR(pp->clk);  		goto err_put_phy_node; @@ -3613,6 +3634,10 @@ static int mvneta_probe(struct platform_device *pdev)  	clk_prepare_enable(pp->clk); +	pp->clk_bus = devm_clk_get(&pdev->dev, "bus"); +	if (!IS_ERR(pp->clk_bus)) +		clk_prepare_enable(pp->clk_bus); +  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	pp->base = devm_ioremap_resource(&pdev->dev, res);  	if (IS_ERR(pp->base)) { @@ -3724,6 +3749,7 @@ err_free_stats:  err_free_ports:  	free_percpu(pp->ports);  err_clk: +	clk_disable_unprepare(pp->clk_bus);  	clk_disable_unprepare(pp->clk);  err_put_phy_node:  	of_node_put(phy_node); @@ -3741,6 +3767,7 @@ static int mvneta_remove(struct platform_device *pdev)  	struct mvneta_port *pp = netdev_priv(dev);  	unregister_netdev(dev); +	clk_disable_unprepare(pp->clk_bus);  	clk_disable_unprepare(pp->clk);  	free_percpu(pp->ports);  	free_percpu(pp->stats); diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index a4beccf1fd46..c797971aefab 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -3061,7 +3061,7 @@ static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port,  		pe = kzalloc(sizeof(*pe), GFP_KERNEL);  		if (!pe) -			return -1; +			return -ENOMEM;  		mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC);  		pe->index = tid; @@ -3077,7 +3077,7 @@ static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port,  	if (pmap == 0) {  		if (add) {  			kfree(pe); -			return -1; +			return -EINVAL;  		}  		mvpp2_prs_hw_inv(priv, pe->index);  		priv->prs_shadow[pe->index].valid = false; diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 715de8affcc9..c7e939945259 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -182,10 +182,17 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist)  		err = mlx4_reset_slave(dev);  	else  		err = mlx4_reset_master(dev); -	BUG_ON(err != 0); +	if (!err) { +		mlx4_err(dev, "device was reset successfully\n"); +	} else { +		/* EEH could have disabled the PCI channel during reset. That's +		 * recoverable and the PCI error flow will handle it. +		 */ +		if (!pci_channel_offline(dev->persist->pdev)) +			BUG_ON(1); +	}  	dev->persist->state |= MLX4_DEVICE_STATE_INTERNAL_ERROR; -	mlx4_err(dev, "device was reset successfully\n");  	mutex_unlock(&persist->device_state_mutex);  	/* At that step HW was already reset, now notify clients */ diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index d48d5793407d..e94ca1c3fc7c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2429,7 +2429,7 @@ err_thread:  	flush_workqueue(priv->mfunc.master.comm_wq);  	destroy_workqueue(priv->mfunc.master.comm_wq);  err_slaves: -	while (--i) { +	while (i--) {  		for (port = 1; port <= MLX4_MAX_PORTS; port++)  			kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);  	} diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index 3348e646db70..a849da92f857 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -318,7 +318,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,  	if (timestamp_en)  		cq_context->flags  |= cpu_to_be32(1 << 19); -	cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); +	cq_context->logsize_usrpage = +		cpu_to_be32((ilog2(nent) << 24) | +			    mlx4_to_hw_uar_index(dev, uar->index));  	cq_context->comp_eqn	    = priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn;  	cq_context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index 038f9ce391e6..1494997c4f7e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -236,6 +236,24 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = {  	.enable		= mlx4_en_phc_enable,  }; +#define MLX4_EN_WRAP_AROUND_SEC	10ULL + +/* This function calculates the max shift that enables the user range + * of MLX4_EN_WRAP_AROUND_SEC values in the cycles register. + */ +static u32 freq_to_shift(u16 freq) +{ +	u32 freq_khz = freq * 1000; +	u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC; +	u64 max_val_cycles_rounded = is_power_of_2(max_val_cycles + 1) ? +		max_val_cycles : roundup_pow_of_two(max_val_cycles) - 1; +	/* calculate max possible multiplier in order to fit in 64bit */ +	u64 max_mul = div_u64(0xffffffffffffffffULL, max_val_cycles_rounded); + +	/* This comes from the reverse of clocksource_khz2mult */ +	return ilog2(div_u64(max_mul * freq_khz, 1000000)); +} +  void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)  {  	struct mlx4_dev *dev = mdev->dev; @@ -254,12 +272,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)  	memset(&mdev->cycles, 0, sizeof(mdev->cycles));  	mdev->cycles.read = mlx4_en_read_clock;  	mdev->cycles.mask = CLOCKSOURCE_MASK(48); -	/* Using shift to make calculation more accurate. Since current HW -	 * clock frequency is 427 MHz, and cycles are given using a 48 bits -	 * register, the biggest shift when calculating using u64, is 14 -	 * (max_cycles * multiplier < 2^64) -	 */ -	mdev->cycles.shift = 14; +	mdev->cycles.shift = freq_to_shift(dev->caps.hca_core_clock);  	mdev->cycles.mult =  		clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);  	mdev->nominal_c_mult = mdev->cycles.mult; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 0c7e3f69a73b..21e2c0960271 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2245,7 +2245,7 @@ static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)  	struct mlx4_en_dev *mdev = en_priv->mdev;  	u64 mac_u64 = mlx4_mac_to_u64(mac); -	if (!is_valid_ether_addr(mac)) +	if (is_multicast_ether_addr(mac))  		return -EINVAL;  	return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64); @@ -2344,8 +2344,6 @@ out:  	/* set offloads */  	priv->dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM |  				      NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL; -	priv->dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; -	priv->dev->features    |= NETIF_F_GSO_UDP_TUNNEL;  }  static void mlx4_en_del_vxlan_offloads(struct work_struct *work) @@ -2356,8 +2354,6 @@ static void mlx4_en_del_vxlan_offloads(struct work_struct *work)  	/* unset offloads */  	priv->dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_RXCSUM |  				      NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL); -	priv->dev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL; -	priv->dev->features    &= ~NETIF_F_GSO_UDP_TUNNEL;  	ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port,  				  VXLAN_STEER_BY_OUTER_MAC, 0); @@ -2980,6 +2976,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,  		priv->rss_hash_fn = ETH_RSS_HASH_TOP;  	} +	if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { +		dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; +		dev->features    |= NETIF_F_GSO_UDP_TUNNEL; +	} +  	mdev->pndev[port] = dev;  	mdev->upper[port] = NULL; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index ee99e67187f5..3904b5fc0b7c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -238,11 +238,11 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)  	stats->collisions = 0;  	stats->rx_dropped = be32_to_cpu(mlx4_en_stats->RDROP);  	stats->rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength); -	stats->rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); +	stats->rx_over_errors = 0;  	stats->rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC);  	stats->rx_frame_errors = 0;  	stats->rx_fifo_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); -	stats->rx_missed_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); +	stats->rx_missed_errors = 0;  	stats->tx_aborted_errors = 0;  	stats->tx_carrier_errors = 0;  	stats->tx_fifo_errors = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c index 12aab5a659d3..02e925d6f734 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c @@ -58,7 +58,8 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,  	} else {  		context->sq_size_stride = ilog2(TXBB_SIZE) - 4;  	} -	context->usr_page = cpu_to_be32(mdev->priv_uar.index); +	context->usr_page = cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev, +					mdev->priv_uar.index));  	context->local_qpn = cpu_to_be32(qpn);  	context->pri_path.ackto = 1 & 0x07;  	context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 41440b2b20a3..86bcfe510e4e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -82,8 +82,7 @@ static int mlx4_alloc_pages(struct mlx4_en_priv *priv,  	/* Not doing get_page() for each frag is a big win  	 * on asymetric workloads. Note we can not use atomic_set().  	 */ -	atomic_add(page_alloc->page_size / frag_info->frag_stride - 1, -		   &page->_count); +	page_ref_add(page, page_alloc->page_size / frag_info->frag_stride - 1);  	return 0;  } @@ -127,7 +126,7 @@ out:  			dma_unmap_page(priv->ddev, page_alloc[i].dma,  				page_alloc[i].page_size, PCI_DMA_FROMDEVICE);  			page = page_alloc[i].page; -			atomic_set(&page->_count, 1); +			set_page_count(page, 1);  			put_page(page);  		}  	} @@ -165,7 +164,7 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv,  		en_dbg(DRV, priv, "  frag %d allocator: - size:%d frags:%d\n",  		       i, ring->page_alloc[i].page_size, -		       atomic_read(&ring->page_alloc[i].page->_count)); +		       page_ref_count(ring->page_alloc[i].page));  	}  	return 0; @@ -177,7 +176,7 @@ out:  		dma_unmap_page(priv->ddev, page_alloc->dma,  			       page_alloc->page_size, PCI_DMA_FROMDEVICE);  		page = page_alloc->page; -		atomic_set(&page->_count, 1); +		set_page_count(page, 1);  		put_page(page);  		page_alloc->page = NULL;  	} diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 4421bf5463f6..e0946ab22010 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -213,7 +213,9 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,  	mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,  				ring->cqn, user_prio, &ring->context);  	if (ring->bf_alloced) -		ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); +		ring->context.usr_page = +			cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev, +							 ring->bf.uar->index));  	err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context,  			       &ring->qp, &ring->qp_state); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 4696053165f8..f613977455e0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -940,9 +940,10 @@ static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)  	if (!priv->eq_table.uar_map[index]) {  		priv->eq_table.uar_map[index] = -			ioremap(pci_resource_start(dev->persist->pdev, 2) + -				((eq->eqn / 4) << PAGE_SHIFT), -				PAGE_SIZE); +			ioremap( +				pci_resource_start(dev->persist->pdev, 2) + +				((eq->eqn / 4) << (dev->uar_page_shift)), +				(1 << (dev->uar_page_shift)));  		if (!priv->eq_table.uar_map[index]) {  			mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n",  				 eq->eqn); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 2c2baab9d880..e97094598b2d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -157,6 +157,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)  		[29] = "802.1ad offload support",  		[31] = "Modifying loopback source checks using UPDATE_QP support",  		[32] = "Loopback source checks support", +		[33] = "RoCEv2 support", +		[34] = "DMFS Sniffer support (UC & MC)"  	};  	int i; @@ -626,6 +628,8 @@ out:  	return err;  } +static void disable_unsupported_roce_caps(void *buf); +  int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)  {  	struct mlx4_cmd_mailbox *mailbox; @@ -738,6 +742,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)  	if (err)  		goto out; +	if (mlx4_is_mfunc(dev)) +		disable_unsupported_roce_caps(outbox);  	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET);  	dev_cap->reserved_qps = 1 << (field & 0xf);  	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET); @@ -805,6 +811,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)  	if (field & 0x80)  		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FS_EN;  	dev_cap->fs_log_max_ucast_qp_range_size = field & 0x1f; +	if (field & 0x20) +		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_UC_MC_SNIFFER;  	MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_BEACON_OFFSET);  	if (field & 0x80)  		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_BEACON; @@ -905,6 +913,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)  		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_EQE_STRIDE;  	MLX4_GET(dev_cap->bmme_flags, outbox,  		 QUERY_DEV_CAP_BMME_FLAGS_OFFSET); +	if (dev_cap->bmme_flags & MLX4_FLAG_ROCE_V1_V2) +		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ROCE_V1_V2;  	if (dev_cap->bmme_flags & MLX4_FLAG_PORT_REMAP)  		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_REMAP;  	MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); @@ -1161,6 +1171,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,  	if (err)  		return err; +	disable_unsupported_roce_caps(outbox->buf);  	/* add port mng change event capability and disable mw type 1  	 * unconditionally to slaves  	 */ @@ -1258,6 +1269,21 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,  	return 0;  } +static void disable_unsupported_roce_caps(void *buf) +{ +	u32 flags; + +	MLX4_GET(flags, buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); +	flags &= ~(1UL << 31); +	MLX4_PUT(buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); +	MLX4_GET(flags, buf, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); +	flags &= ~(1UL << 24); +	MLX4_PUT(buf, flags, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); +	MLX4_GET(flags, buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); +	flags &= ~(MLX4_FLAG_ROCE_V1_V2); +	MLX4_PUT(buf, flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); +} +  int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,  			    struct mlx4_vhcr *vhcr,  			    struct mlx4_cmd_mailbox *inbox, @@ -2239,7 +2265,8 @@ struct mlx4_config_dev {  	__be32	rsvd1[3];  	__be16	vxlan_udp_dport;  	__be16	rsvd2; -	__be32	rsvd3; +	__be16  roce_v2_entropy; +	__be16  roce_v2_udp_dport;  	__be32	roce_flags;  	__be32	rsvd4[25];  	__be16	rsvd5; @@ -2248,6 +2275,7 @@ struct mlx4_config_dev {  };  #define MLX4_VXLAN_UDP_DPORT (1 << 0) +#define MLX4_ROCE_V2_UDP_DPORT BIT(3)  #define MLX4_DISABLE_RX_PORT BIT(18)  static int mlx4_CONFIG_DEV_set(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev) @@ -2365,6 +2393,18 @@ int mlx4_disable_rx_port_check(struct mlx4_dev *dev, bool dis)  	return mlx4_CONFIG_DEV_set(dev, &config_dev);  } +int mlx4_config_roce_v2_port(struct mlx4_dev *dev, u16 udp_port) +{ +	struct mlx4_config_dev config_dev; + +	memset(&config_dev, 0, sizeof(config_dev)); +	config_dev.update_flags    = cpu_to_be32(MLX4_ROCE_V2_UDP_DPORT); +	config_dev.roce_v2_udp_dport = cpu_to_be16(udp_port); + +	return mlx4_CONFIG_DEV_set(dev, &config_dev); +} +EXPORT_SYMBOL_GPL(mlx4_config_roce_v2_port); +  int mlx4_virt2phy_port_map(struct mlx4_dev *dev, u32 port1, u32 port2)  {  	struct mlx4_cmd_mailbox *mailbox; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index f1b6d219e445..f8674ae62752 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -168,6 +168,20 @@ struct mlx4_port_config {  static atomic_t pf_loading = ATOMIC_INIT(0); +static inline void mlx4_set_num_reserved_uars(struct mlx4_dev *dev, +					      struct mlx4_dev_cap *dev_cap) +{ +	/* The reserved_uars is calculated by system page size unit. +	 * Therefore, adjustment is added when the uar page size is less +	 * than the system page size +	 */ +	dev->caps.reserved_uars	= +		max_t(int, +		      mlx4_get_num_reserved_uar(dev), +		      dev_cap->reserved_uars / +			(1 << (PAGE_SHIFT - dev->uar_page_shift))); +} +  int mlx4_check_port_params(struct mlx4_dev *dev,  			   enum mlx4_port_type *port_type)  { @@ -386,8 +400,6 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)  	dev->caps.reserved_mtts      = dev_cap->reserved_mtts;  	dev->caps.reserved_mrws	     = dev_cap->reserved_mrws; -	/* The first 128 UARs are used for EQ doorbells */ -	dev->caps.reserved_uars	     = max_t(int, 128, dev_cap->reserved_uars);  	dev->caps.reserved_pds	     = dev_cap->reserved_pds;  	dev->caps.reserved_xrcds     = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ?  					dev_cap->reserved_xrcds : 0; @@ -405,6 +417,15 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)  	dev->caps.max_gso_sz	     = dev_cap->max_gso_sz;  	dev->caps.max_rss_tbl_sz     = dev_cap->max_rss_tbl_sz; +	/* Save uar page shift */ +	if (!mlx4_is_slave(dev)) { +		/* Virtual PCI function needs to determine UAR page size from +		 * firmware. Only master PCI function can set the uar page size +		 */ +		dev->uar_page_shift = DEFAULT_UAR_PAGE_SHIFT; +		mlx4_set_num_reserved_uars(dev, dev_cap); +	} +  	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN) {  		struct mlx4_init_hca_param hca_param; @@ -815,16 +836,25 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)  		return -ENODEV;  	} -	/* slave gets uar page size from QUERY_HCA fw command */ -	dev->caps.uar_page_size = 1 << (hca_param.uar_page_sz + 12); +	/* Set uar_page_shift for VF */ +	dev->uar_page_shift = hca_param.uar_page_sz + 12; -	/* TODO: relax this assumption */ -	if (dev->caps.uar_page_size != PAGE_SIZE) { -		mlx4_err(dev, "UAR size:%d != kernel PAGE_SIZE of %ld\n", -			 dev->caps.uar_page_size, PAGE_SIZE); -		return -ENODEV; +	/* Make sure the master uar page size is valid */ +	if (dev->uar_page_shift > PAGE_SHIFT) { +		mlx4_err(dev, +			 "Invalid configuration: uar page size is larger than system page size\n"); +		return  -ENODEV;  	} +	/* Set reserved_uars based on the uar_page_shift */ +	mlx4_set_num_reserved_uars(dev, &dev_cap); + +	/* Although uar page size in FW differs from system page size, +	 * upper software layers (mlx4_ib, mlx4_en and part of mlx4_core) +	 * still works with assumption that uar page size == system page size +	 */ +	dev->caps.uar_page_size = PAGE_SIZE; +  	memset(&func_cap, 0, sizeof(func_cap));  	err = mlx4_QUERY_FUNC_CAP(dev, 0, &func_cap);  	if (err) { @@ -1226,6 +1256,7 @@ err_set_port:  static int mlx4_mf_bond(struct mlx4_dev *dev)  {  	int err = 0; +	int nvfs;  	struct mlx4_slaves_pport slaves_port1;  	struct mlx4_slaves_pport slaves_port2;  	DECLARE_BITMAP(slaves_port_1_2, MLX4_MFUNC_MAX); @@ -1242,11 +1273,18 @@ static int mlx4_mf_bond(struct mlx4_dev *dev)  		return -EINVAL;  	} +	/* number of virtual functions is number of total functions minus one +	 * physical function for each port. +	 */ +	nvfs = bitmap_weight(slaves_port1.slaves, dev->persist->num_vfs + 1) + +		bitmap_weight(slaves_port2.slaves, dev->persist->num_vfs + 1) - 2; +  	/* limit on maximum allowed VFs */ -	if ((bitmap_weight(slaves_port1.slaves, dev->persist->num_vfs + 1) + -	    bitmap_weight(slaves_port2.slaves, dev->persist->num_vfs + 1)) > -	    MAX_MF_BOND_ALLOWED_SLAVES) +	if (nvfs > MAX_MF_BOND_ALLOWED_SLAVES) { +		mlx4_warn(dev, "HA mode is not supported for %d VFs (max %d are allowed)\n", +			  nvfs, MAX_MF_BOND_ALLOWED_SLAVES);  		return -EINVAL; +	}  	if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) {  		mlx4_warn(dev, "HA mode unsupported for NON DMFS steering\n"); @@ -2179,8 +2217,12 @@ static int mlx4_init_hca(struct mlx4_dev *dev)  		dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1; -		init_hca.log_uar_sz = ilog2(dev->caps.num_uars); -		init_hca.uar_page_sz = PAGE_SHIFT - 12; +		/* Always set UAR page size 4KB, set log_uar_sz accordingly */ +		init_hca.log_uar_sz = ilog2(dev->caps.num_uars) + +				      PAGE_SHIFT - +				      DEFAULT_UAR_PAGE_SHIFT; +		init_hca.uar_page_sz = DEFAULT_UAR_PAGE_SHIFT - 12; +  		init_hca.mw_enabled = 0;  		if (dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW ||  		    dev->caps.bmme_flags & MLX4_BMME_FLAG_TYPE_2_WIN) diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 1d4e2e054647..42d8de892bfe 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -752,8 +752,10 @@ static const u8 __promisc_mode[] = {  	[MLX4_FS_REGULAR]   = 0x0,  	[MLX4_FS_ALL_DEFAULT] = 0x1,  	[MLX4_FS_MC_DEFAULT] = 0x3, -	[MLX4_FS_UC_SNIFFER] = 0x4, -	[MLX4_FS_MC_SNIFFER] = 0x5, +	[MLX4_FS_MIRROR_RX_PORT] = 0x4, +	[MLX4_FS_MIRROR_SX_PORT] = 0x5, +	[MLX4_FS_UC_SNIFFER] = 0x6, +	[MLX4_FS_MC_SNIFFER] = 0x7,  };  int mlx4_map_sw_to_hw_steering_mode(struct mlx4_dev *dev, diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 2404c22ad2b2..7baef52db6b7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -780,7 +780,10 @@ struct mlx4_set_port_general_context {  	u16 reserved1;  	u8 v_ignore_fcs;  	u8 flags; -	u8 ignore_fcs; +	union { +		u8 ignore_fcs; +		u8 roce_mode; +	};  	u8 reserved2;  	__be16 mtu;  	u8 pptx; diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c index 609c59dc854e..b3cc3ab63799 100644 --- a/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -269,9 +269,15 @@ EXPORT_SYMBOL_GPL(mlx4_bf_free);  int mlx4_init_uar_table(struct mlx4_dev *dev)  { -	if (dev->caps.num_uars <= 128) { -		mlx4_err(dev, "Only %d UAR pages (need more than 128)\n", -			 dev->caps.num_uars); +	int num_reserved_uar = mlx4_get_num_reserved_uar(dev); + +	mlx4_dbg(dev, "uar_page_shift = %d", dev->uar_page_shift); +	mlx4_dbg(dev, "Effective reserved_uars=%d", dev->caps.reserved_uars); + +	if (dev->caps.num_uars <= num_reserved_uar) { +		mlx4_err( +			dev, "Only %d UAR pages (need more than %d)\n", +			dev->caps.num_uars, num_reserved_uar);  		mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n");  		return -ENODEV;  	} diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index f2550425c251..211c65087997 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -193,10 +193,10 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)  	if (need_mf_bond) {  		if (port == 1) {  			mutex_lock(&table->mutex); -			mutex_lock(&dup_table->mutex); +			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);  		} else {  			mutex_lock(&dup_table->mutex); -			mutex_lock(&table->mutex); +			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);  		}  	} else {  		mutex_lock(&table->mutex); @@ -389,10 +389,10 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)  	if (dup) {  		if (port == 1) {  			mutex_lock(&table->mutex); -			mutex_lock(&dup_table->mutex); +			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);  		} else {  			mutex_lock(&dup_table->mutex); -			mutex_lock(&table->mutex); +			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);  		}  	} else {  		mutex_lock(&table->mutex); @@ -479,10 +479,10 @@ int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)  	if (dup) {  		if (port == 1) {  			mutex_lock(&table->mutex); -			mutex_lock(&dup_table->mutex); +			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);  		} else {  			mutex_lock(&dup_table->mutex); -			mutex_lock(&table->mutex); +			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);  		}  	} else {  		mutex_lock(&table->mutex); @@ -588,10 +588,10 @@ int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,  	if (need_mf_bond) {  		if (port == 1) {  			mutex_lock(&table->mutex); -			mutex_lock(&dup_table->mutex); +			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);  		} else {  			mutex_lock(&dup_table->mutex); -			mutex_lock(&table->mutex); +			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);  		}  	} else {  		mutex_lock(&table->mutex); @@ -764,10 +764,10 @@ void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)  	if (dup) {  		if (port == 1) {  			mutex_lock(&table->mutex); -			mutex_lock(&dup_table->mutex); +			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);  		} else {  			mutex_lock(&dup_table->mutex); -			mutex_lock(&table->mutex); +			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);  		}  	} else {  		mutex_lock(&table->mutex); @@ -1520,6 +1520,8 @@ int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)  	return err;  } +#define SET_PORT_ROCE_2_FLAGS          0x10 +#define MLX4_SET_PORT_ROCE_V1_V2       0x2  int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,  			  u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)  { @@ -1539,6 +1541,11 @@ int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,  	context->pprx = (pprx * (!pfcrx)) << 7;  	context->pfcrx = pfcrx; +	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) { +		context->flags |= SET_PORT_ROCE_2_FLAGS; +		context->roce_mode |= +			MLX4_SET_PORT_ROCE_V1_V2 << 4; +	}  	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;  	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,  		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 168823dde79f..d1cd9c32a9ae 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -167,6 +167,12 @@ static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,  		context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;  	} +	if ((cur_state == MLX4_QP_STATE_RTR) && +	    (new_state == MLX4_QP_STATE_RTS) && +	    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) +		context->roce_entropy = +			cpu_to_be16(mlx4_qp_roce_entropy(dev, qp->qpn)); +  	*(__be32 *) mailbox->buf = cpu_to_be32(optpar);  	memcpy(mailbox->buf + 8, context, sizeof *context); @@ -921,3 +927,23 @@ int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt,  	return 0;  }  EXPORT_SYMBOL_GPL(mlx4_qp_to_ready); + +u16 mlx4_qp_roce_entropy(struct mlx4_dev *dev, u32 qpn) +{ +	struct mlx4_qp_context context; +	struct mlx4_qp qp; +	int err; + +	qp.qpn = qpn; +	err = mlx4_qp_query(dev, &qp, &context); +	if (!err) { +		u32 dest_qpn = be32_to_cpu(context.remote_qpn) & 0xffffff; +		u16 folded_dst = folded_qp(dest_qpn); +		u16 folded_src = folded_qp(qpn); + +		return (dest_qpn != qpn) ? +			((folded_dst ^ folded_src) | 0xC000) : +			folded_src | 0xC000; +	} +	return 0xdead; +} diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index b46dbe29ef6c..25ce1b030a00 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -915,11 +915,13 @@ static int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port,  	spin_lock_irq(mlx4_tlock(dev));  	r = find_res(dev, counter_index, RES_COUNTER); -	if (!r || r->owner != slave) +	if (!r || r->owner != slave) {  		ret = -EINVAL; -	counter = container_of(r, struct res_counter, com); -	if (!counter->port) -		counter->port = port; +	} else { +		counter = container_of(r, struct res_counter, com); +		if (!counter->port) +			counter->port = port; +	}  	spin_unlock_irq(mlx4_tlock(dev));  	return ret; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 9ea49a893323..81b2013ef968 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -39,8 +39,8 @@  #include <linux/mlx5/qp.h>  #include <linux/mlx5/cq.h>  #include <linux/mlx5/vport.h> +#include <linux/mlx5/transobj.h>  #include "wq.h" -#include "transobj.h"  #include "mlx5_core.h"  #define MLX5E_MAX_NUM_TC	8 @@ -223,6 +223,7 @@ struct mlx5e_pport_stats {  static const char rq_stats_strings[][ETH_GSTRING_LEN] = {  	"packets", +	"bytes",  	"csum_none",  	"csum_sw",  	"lro_packets", @@ -232,16 +233,18 @@ static const char rq_stats_strings[][ETH_GSTRING_LEN] = {  struct mlx5e_rq_stats {  	u64 packets; +	u64 bytes;  	u64 csum_none;  	u64 csum_sw;  	u64 lro_packets;  	u64 lro_bytes;  	u64 wqe_err; -#define NUM_RQ_STATS 6 +#define NUM_RQ_STATS 7  };  static const char sq_stats_strings[][ETH_GSTRING_LEN] = {  	"packets", +	"bytes",  	"tso_packets",  	"tso_bytes",  	"csum_offload_none", @@ -253,6 +256,7 @@ static const char sq_stats_strings[][ETH_GSTRING_LEN] = {  struct mlx5e_sq_stats {  	u64 packets; +	u64 bytes;  	u64 tso_packets;  	u64 tso_bytes;  	u64 csum_offload_none; @@ -260,7 +264,7 @@ struct mlx5e_sq_stats {  	u64 wake;  	u64 dropped;  	u64 nop; -#define NUM_SQ_STATS 8 +#define NUM_SQ_STATS 9  };  struct mlx5e_stats { @@ -304,14 +308,9 @@ enum {  	MLX5E_RQ_STATE_POST_WQES_ENABLE,  }; -enum cq_flags { -	MLX5E_CQ_HAS_CQES = 1, -}; -  struct mlx5e_cq {  	/* data path - accessed per cqe */  	struct mlx5_cqwq           wq; -	unsigned long              flags;  	/* data path - accessed per napi poll */  	struct napi_struct        *napi; @@ -452,6 +451,8 @@ enum mlx5e_traffic_types {  	MLX5E_NUM_TT,  }; +#define IS_HASHING_TT(tt) (tt != MLX5E_TT_ANY) +  enum mlx5e_rqt_ix {  	MLX5E_INDIRECTION_RQT,  	MLX5E_SINGLE_RQ_RQT, @@ -515,7 +516,7 @@ struct mlx5e_priv {  	struct mlx5_uar            cq_uar;  	u32                        pdn;  	u32                        tdn; -	struct mlx5_core_mr        mr; +	struct mlx5_core_mkey      mkey;  	struct mlx5e_rq            drop_rq;  	struct mlx5e_channel     **channel; @@ -618,9 +619,12 @@ void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv);  void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv);  int mlx5e_redirect_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix); +void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv);  int mlx5e_open_locked(struct net_device *netdev);  int mlx5e_close_locked(struct net_device *netdev); +void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len, +				   int num_channels);  static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq,  				      struct mlx5e_tx_wqe *wqe, int bf_sz) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c index be6543570b2b..2018eebe1531 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c @@ -62,10 +62,11 @@ static void mlx5e_timestamp_overflow(struct work_struct *work)  	struct delayed_work *dwork = to_delayed_work(work);  	struct mlx5e_tstamp *tstamp = container_of(dwork, struct mlx5e_tstamp,  						   overflow_work); +	unsigned long flags; -	write_lock(&tstamp->lock); +	write_lock_irqsave(&tstamp->lock, flags);  	timecounter_read(&tstamp->clock); -	write_unlock(&tstamp->lock); +	write_unlock_irqrestore(&tstamp->lock, flags);  	schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period);  } @@ -136,10 +137,11 @@ static int mlx5e_ptp_settime(struct ptp_clock_info *ptp,  	struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,  						   ptp_info);  	u64 ns = timespec64_to_ns(ts); +	unsigned long flags; -	write_lock(&tstamp->lock); +	write_lock_irqsave(&tstamp->lock, flags);  	timecounter_init(&tstamp->clock, &tstamp->cycles, ns); -	write_unlock(&tstamp->lock); +	write_unlock_irqrestore(&tstamp->lock, flags);  	return 0;  } @@ -150,10 +152,11 @@ static int mlx5e_ptp_gettime(struct ptp_clock_info *ptp,  	struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,  						   ptp_info);  	u64 ns; +	unsigned long flags; -	write_lock(&tstamp->lock); +	write_lock_irqsave(&tstamp->lock, flags);  	ns = timecounter_read(&tstamp->clock); -	write_unlock(&tstamp->lock); +	write_unlock_irqrestore(&tstamp->lock, flags);  	*ts = ns_to_timespec64(ns); @@ -164,10 +167,11 @@ static int mlx5e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)  {  	struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,  						   ptp_info); +	unsigned long flags; -	write_lock(&tstamp->lock); +	write_lock_irqsave(&tstamp->lock, flags);  	timecounter_adjtime(&tstamp->clock, delta); -	write_unlock(&tstamp->lock); +	write_unlock_irqrestore(&tstamp->lock, flags);  	return 0;  } @@ -176,6 +180,7 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)  {  	u64 adj;  	u32 diff; +	unsigned long flags;  	int neg_adj = 0;  	struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,  						  ptp_info); @@ -189,11 +194,11 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)  	adj *= delta;  	diff = div_u64(adj, 1000000000ULL); -	write_lock(&tstamp->lock); +	write_lock_irqsave(&tstamp->lock, flags);  	timecounter_read(&tstamp->clock);  	tstamp->cycles.mult = neg_adj ? tstamp->nominal_c_mult - diff :  					tstamp->nominal_c_mult + diff; -	write_unlock(&tstamp->lock); +	write_unlock_irqrestore(&tstamp->lock, flags);  	return 0;  } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 65624ac65b4c..5abeb00fceb8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -385,6 +385,8 @@ static int mlx5e_set_channels(struct net_device *dev,  		mlx5e_close_locked(dev);  	priv->params.num_channels = count; +	mlx5e_build_default_indir_rqt(priv->params.indirection_rqt, +				      MLX5E_INDIR_RQT_SIZE, count);  	if (was_opened)  		err = mlx5e_open_locked(dev); @@ -703,18 +705,36 @@ static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,  	return 0;  } +static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen) +{ +	struct mlx5_core_dev *mdev = priv->mdev; +	void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx); +	int i; + +	MLX5_SET(modify_tir_in, in, bitmask.hash, 1); +	mlx5e_build_tir_ctx_hash(tirc, priv); + +	for (i = 0; i < MLX5E_NUM_TT; i++) +		if (IS_HASHING_TT(i)) +			mlx5_core_modify_tir(mdev, priv->tirn[i], in, inlen); +} +  static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,  			  const u8 *key, const u8 hfunc)  {  	struct mlx5e_priv *priv = netdev_priv(dev); -	bool close_open; -	int err = 0; +	int inlen = MLX5_ST_SZ_BYTES(modify_tir_in); +	void *in;  	if ((hfunc != ETH_RSS_HASH_NO_CHANGE) &&  	    (hfunc != ETH_RSS_HASH_XOR) &&  	    (hfunc != ETH_RSS_HASH_TOP))  		return -EINVAL; +	in = mlx5_vzalloc(inlen); +	if (!in) +		return -ENOMEM; +  	mutex_lock(&priv->state_lock);  	if (indir) { @@ -723,11 +743,6 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,  		mlx5e_redirect_rqt(priv, MLX5E_INDIRECTION_RQT);  	} -	close_open = (key || (hfunc != ETH_RSS_HASH_NO_CHANGE)) && -		     test_bit(MLX5E_STATE_OPENED, &priv->state); -	if (close_open) -		mlx5e_close_locked(dev); -  	if (key)  		memcpy(priv->params.toeplitz_hash_key, key,  		       sizeof(priv->params.toeplitz_hash_key)); @@ -735,12 +750,13 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,  	if (hfunc != ETH_RSS_HASH_NO_CHANGE)  		priv->params.rss_hfunc = hfunc; -	if (close_open) -		err = mlx5e_open_locked(priv->netdev); +	mlx5e_modify_tirs_hash(priv, in, inlen);  	mutex_unlock(&priv->state_lock); -	return err; +	kvfree(in); + +	return 0;  }  static int mlx5e_get_rxnfc(struct net_device *netdev, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index c56d91a2812b..0c49951606b6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -141,6 +141,10 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)  		return;  	/* Collect firts the SW counters and then HW for consistency */ +	s->rx_packets		= 0; +	s->rx_bytes		= 0; +	s->tx_packets		= 0; +	s->tx_bytes		= 0;  	s->tso_packets		= 0;  	s->tso_bytes		= 0;  	s->tx_queue_stopped	= 0; @@ -155,6 +159,8 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)  	for (i = 0; i < priv->params.num_channels; i++) {  		rq_stats = &priv->channel[i]->rq.stats; +		s->rx_packets	+= rq_stats->packets; +		s->rx_bytes	+= rq_stats->bytes;  		s->lro_packets	+= rq_stats->lro_packets;  		s->lro_bytes	+= rq_stats->lro_bytes;  		s->rx_csum_none	+= rq_stats->csum_none; @@ -164,6 +170,8 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)  		for (j = 0; j < priv->params.num_tc; j++) {  			sq_stats = &priv->channel[i]->sq[j].stats; +			s->tx_packets		+= sq_stats->packets; +			s->tx_bytes		+= sq_stats->bytes;  			s->tso_packets		+= sq_stats->tso_packets;  			s->tso_bytes		+= sq_stats->tso_bytes;  			s->tx_queue_stopped	+= sq_stats->stopped; @@ -225,23 +233,6 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)  	s->tx_broadcast_bytes   =  		MLX5_GET_CTR(out, transmitted_eth_broadcast.octets); -	s->rx_packets = -		s->rx_unicast_packets + -		s->rx_multicast_packets + -		s->rx_broadcast_packets; -	s->rx_bytes = -		s->rx_unicast_bytes + -		s->rx_multicast_bytes + -		s->rx_broadcast_bytes; -	s->tx_packets = -		s->tx_unicast_packets + -		s->tx_multicast_packets + -		s->tx_broadcast_packets; -	s->tx_bytes = -		s->tx_unicast_bytes + -		s->tx_multicast_bytes + -		s->tx_broadcast_bytes; -  	/* Update calculated offload counters */  	s->tx_csum_offload = s->tx_packets - tx_offload_none;  	s->rx_csum_good    = s->rx_packets - s->rx_csum_none - @@ -982,7 +973,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,  	c->cpu      = cpu;  	c->pdev     = &priv->mdev->pdev->dev;  	c->netdev   = priv->netdev; -	c->mkey_be  = cpu_to_be32(priv->mr.key); +	c->mkey_be  = cpu_to_be32(priv->mkey.key);  	c->num_tc   = priv->params.num_tc;  	mlx5e_build_channeltc_to_txq_map(priv, ix); @@ -1199,7 +1190,6 @@ static void mlx5e_fill_indir_rqt_rqns(struct mlx5e_priv *priv, void *rqtc)  			ix = mlx5e_bits_invert(i, MLX5E_LOG_INDIR_RQT_SIZE);  		ix = priv->params.indirection_rqt[ix]; -		ix = ix % priv->params.num_channels;  		MLX5_SET(rqtc, rqtc, rq_num[i],  			 test_bit(MLX5E_STATE_OPENED, &priv->state) ?  			 priv->channel[ix]->rq.rqn : @@ -1317,7 +1307,22 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv)  			      lro_timer_supported_periods[2]));  } -static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt) +void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv) +{ +	MLX5_SET(tirc, tirc, rx_hash_fn, +		 mlx5e_rx_hash_fn(priv->params.rss_hfunc)); +	if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) { +		void *rss_key = MLX5_ADDR_OF(tirc, tirc, +					     rx_hash_toeplitz_key); +		size_t len = MLX5_FLD_SZ_BYTES(tirc, +					       rx_hash_toeplitz_key); + +		MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); +		memcpy(rss_key, priv->params.toeplitz_hash_key, len); +	} +} + +static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)  {  	struct mlx5_core_dev *mdev = priv->mdev; @@ -1325,6 +1330,7 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)  	void *tirc;  	int inlen;  	int err; +	int tt;  	inlen = MLX5_ST_SZ_BYTES(modify_tir_in);  	in = mlx5_vzalloc(inlen); @@ -1336,7 +1342,11 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)  	mlx5e_build_tir_ctx_lro(tirc, priv); -	err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen); +	for (tt = 0; tt < MLX5E_NUM_TT; tt++) { +		err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen); +		if (err) +			break; +	}  	kvfree(in); @@ -1672,17 +1682,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt)  	default:  		MLX5_SET(tirc, tirc, indirect_table,  			 priv->rqtn[MLX5E_INDIRECTION_RQT]); -		MLX5_SET(tirc, tirc, rx_hash_fn, -			 mlx5e_rx_hash_fn(priv->params.rss_hfunc)); -		if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) { -			void *rss_key = MLX5_ADDR_OF(tirc, tirc, -						     rx_hash_toeplitz_key); -			size_t len = MLX5_FLD_SZ_BYTES(tirc, -						       rx_hash_toeplitz_key); - -			MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); -			memcpy(rss_key, priv->params.toeplitz_hash_key, len); -		} +		mlx5e_build_tir_ctx_hash(tirc, priv);  		break;  	} @@ -1885,8 +1885,10 @@ static int mlx5e_set_features(struct net_device *netdev,  			mlx5e_close_locked(priv->netdev);  		priv->params.lro_en = !!(features & NETIF_F_LRO); -		mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV4_TCP); -		mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV6_TCP); +		err = mlx5e_modify_tirs_lro(priv); +		if (err) +			mlx5_core_warn(priv->mdev, "lro modify failed, %d\n", +				       err);  		if (was_opened)  			err = mlx5e_open_locked(priv->netdev); @@ -2024,18 +2026,37 @@ static int mlx5e_get_vf_stats(struct net_device *dev,  					    vf_stats);  } -static struct net_device_ops mlx5e_netdev_ops = { +static const struct net_device_ops mlx5e_netdev_ops_basic = { +	.ndo_open                = mlx5e_open, +	.ndo_stop                = mlx5e_close, +	.ndo_start_xmit          = mlx5e_xmit, +	.ndo_get_stats64         = mlx5e_get_stats, +	.ndo_set_rx_mode         = mlx5e_set_rx_mode, +	.ndo_set_mac_address     = mlx5e_set_mac, +	.ndo_vlan_rx_add_vid     = mlx5e_vlan_rx_add_vid, +	.ndo_vlan_rx_kill_vid    = mlx5e_vlan_rx_kill_vid, +	.ndo_set_features        = mlx5e_set_features, +	.ndo_change_mtu          = mlx5e_change_mtu, +	.ndo_do_ioctl            = mlx5e_ioctl, +}; + +static const struct net_device_ops mlx5e_netdev_ops_sriov = {  	.ndo_open                = mlx5e_open,  	.ndo_stop                = mlx5e_close,  	.ndo_start_xmit          = mlx5e_xmit,  	.ndo_get_stats64         = mlx5e_get_stats,  	.ndo_set_rx_mode         = mlx5e_set_rx_mode,  	.ndo_set_mac_address     = mlx5e_set_mac, -	.ndo_vlan_rx_add_vid	 = mlx5e_vlan_rx_add_vid, -	.ndo_vlan_rx_kill_vid	 = mlx5e_vlan_rx_kill_vid, +	.ndo_vlan_rx_add_vid     = mlx5e_vlan_rx_add_vid, +	.ndo_vlan_rx_kill_vid    = mlx5e_vlan_rx_kill_vid,  	.ndo_set_features        = mlx5e_set_features, -	.ndo_change_mtu		 = mlx5e_change_mtu, -	.ndo_do_ioctl		 = mlx5e_ioctl, +	.ndo_change_mtu          = mlx5e_change_mtu, +	.ndo_do_ioctl            = mlx5e_ioctl, +	.ndo_set_vf_mac          = mlx5e_set_vf_mac, +	.ndo_set_vf_vlan         = mlx5e_set_vf_vlan, +	.ndo_get_vf_config       = mlx5e_get_vf_config, +	.ndo_set_vf_link_state   = mlx5e_set_vf_link_state, +	.ndo_get_vf_stats        = mlx5e_get_vf_stats,  };  static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) @@ -2070,12 +2091,20 @@ u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev)  	       2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/;  } +void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len, +				   int num_channels) +{ +	int i; + +	for (i = 0; i < len; i++) +		indirection_rqt[i] = i % num_channels; +} +  static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,  				    struct net_device *netdev,  				    int num_channels)  {  	struct mlx5e_priv *priv = netdev_priv(netdev); -	int i;  	priv->params.log_sq_size           =  		MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE; @@ -2099,8 +2128,8 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,  	netdev_rss_key_fill(priv->params.toeplitz_hash_key,  			    sizeof(priv->params.toeplitz_hash_key)); -	for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++) -		priv->params.indirection_rqt[i] = i % num_channels; +	mlx5e_build_default_indir_rqt(priv->params.indirection_rqt, +				      MLX5E_INDIR_RQT_SIZE, num_channels);  	priv->params.lro_wqe_sz            =  		MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ; @@ -2137,18 +2166,11 @@ static void mlx5e_build_netdev(struct net_device *netdev)  	SET_NETDEV_DEV(netdev, &mdev->pdev->dev); -	if (priv->params.num_tc > 1) -		mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue; - -	if (MLX5_CAP_GEN(mdev, vport_group_manager)) { -		mlx5e_netdev_ops.ndo_set_vf_mac = mlx5e_set_vf_mac; -		mlx5e_netdev_ops.ndo_set_vf_vlan = mlx5e_set_vf_vlan; -		mlx5e_netdev_ops.ndo_get_vf_config = mlx5e_get_vf_config; -		mlx5e_netdev_ops.ndo_set_vf_link_state = mlx5e_set_vf_link_state; -		mlx5e_netdev_ops.ndo_get_vf_stats = mlx5e_get_vf_stats; -	} +	if (MLX5_CAP_GEN(mdev, vport_group_manager)) +		netdev->netdev_ops = &mlx5e_netdev_ops_sriov; +	else +		netdev->netdev_ops = &mlx5e_netdev_ops_basic; -	netdev->netdev_ops        = &mlx5e_netdev_ops;  	netdev->watchdog_timeo    = 15 * HZ;  	netdev->ethtool_ops	  = &mlx5e_ethtool_ops; @@ -2182,7 +2204,7 @@ static void mlx5e_build_netdev(struct net_device *netdev)  }  static int mlx5e_create_mkey(struct mlx5e_priv *priv, u32 pdn, -			     struct mlx5_core_mr *mr) +			     struct mlx5_core_mkey *mkey)  {  	struct mlx5_core_dev *mdev = priv->mdev;  	struct mlx5_create_mkey_mbox_in *in; @@ -2198,7 +2220,7 @@ static int mlx5e_create_mkey(struct mlx5e_priv *priv, u32 pdn,  	in->seg.flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64);  	in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); -	err = mlx5_core_create_mkey(mdev, mr, in, sizeof(*in), NULL, NULL, +	err = mlx5_core_create_mkey(mdev, mkey, in, sizeof(*in), NULL, NULL,  				    NULL);  	kvfree(in); @@ -2241,13 +2263,13 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)  		goto err_unmap_free_uar;  	} -	err = mlx5_alloc_transport_domain(mdev, &priv->tdn); +	err = mlx5_core_alloc_transport_domain(mdev, &priv->tdn);  	if (err) {  		mlx5_core_err(mdev, "alloc td failed, %d\n", err);  		goto err_dealloc_pd;  	} -	err = mlx5e_create_mkey(priv, priv->pdn, &priv->mr); +	err = mlx5e_create_mkey(priv, priv->pdn, &priv->mkey);  	if (err) {  		mlx5_core_err(mdev, "create mkey failed, %d\n", err);  		goto err_dealloc_transport_domain; @@ -2321,10 +2343,10 @@ err_destroy_tises:  	mlx5e_destroy_tises(priv);  err_destroy_mkey: -	mlx5_core_destroy_mkey(mdev, &priv->mr); +	mlx5_core_destroy_mkey(mdev, &priv->mkey);  err_dealloc_transport_domain: -	mlx5_dealloc_transport_domain(mdev, priv->tdn); +	mlx5_core_dealloc_transport_domain(mdev, priv->tdn);  err_dealloc_pd:  	mlx5_core_dealloc_pd(mdev, priv->pdn); @@ -2355,8 +2377,8 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)  	mlx5e_destroy_rqt(priv, MLX5E_INDIRECTION_RQT);  	mlx5e_close_drop_rq(priv);  	mlx5e_destroy_tises(priv); -	mlx5_core_destroy_mkey(priv->mdev, &priv->mr); -	mlx5_dealloc_transport_domain(priv->mdev, priv->tdn); +	mlx5_core_destroy_mkey(priv->mdev, &priv->mkey); +	mlx5_core_dealloc_transport_domain(priv->mdev, priv->tdn);  	mlx5_core_dealloc_pd(priv->mdev, priv->pdn);  	mlx5_unmap_free_uar(priv->mdev, &priv->cq_uar);  	free_netdev(netdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index dd959d929aad..59658b9d05d1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -230,10 +230,6 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)  	struct mlx5e_rq *rq = container_of(cq, struct mlx5e_rq, cq);  	int work_done; -	/* avoid accessing cq (dma coherent memory) if not needed */ -	if (!test_and_clear_bit(MLX5E_CQ_HAS_CQES, &cq->flags)) -		return 0; -  	for (work_done = 0; work_done < budget; work_done++) {  		struct mlx5e_rx_wqe *wqe;  		struct mlx5_cqe64 *cqe; @@ -267,6 +263,7 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)  		mlx5e_build_rx_skb(cqe, rq, skb);  		rq->stats.packets++; +		rq->stats.bytes += be32_to_cpu(cqe->byte_cnt);  		napi_gro_receive(cq->napi, skb);  wq_ll_pop: @@ -279,8 +276,5 @@ wq_ll_pop:  	/* ensure cq space is freed before enabling more cqes */  	wmb(); -	if (work_done == budget) -		set_bit(MLX5E_CQ_HAS_CQES, &cq->flags); -  	return work_done;  } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 2c3fba0fff54..bb4eeeb007de 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -179,6 +179,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)  	unsigned int skb_len = skb->len;  	u8  opcode = MLX5_OPCODE_SEND;  	dma_addr_t dma_addr = 0; +	unsigned int num_bytes;  	bool bf = false;  	u16 headlen;  	u16 ds_cnt; @@ -204,8 +205,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)  		opcode       = MLX5_OPCODE_LSO;  		ihs          = skb_transport_offset(skb) + tcp_hdrlen(skb);  		payload_len  = skb->len - ihs; -		wi->num_bytes = skb->len + -				(skb_shinfo(skb)->gso_segs - 1) * ihs; +		num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs;  		sq->stats.tso_packets++;  		sq->stats.tso_bytes += payload_len;  	} else { @@ -213,9 +213,11 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)  		     !skb->xmit_more &&  		     !skb_shinfo(skb)->nr_frags;  		ihs = mlx5e_get_inline_hdr_size(sq, skb, bf); -		wi->num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN); +		num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);  	} +	wi->num_bytes = num_bytes; +  	if (skb_vlan_tag_present(skb)) {  		mlx5e_insert_vlan(eseg->inline_hdr_start, skb, ihs, &skb_data,  				  &skb_len); @@ -307,6 +309,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)  	sq->bf_budget = bf ? sq->bf_budget - 1 : 0;  	sq->stats.packets++; +	sq->stats.bytes += num_bytes;  	return NETDEV_TX_OK;  dma_unmap_wqe_err: @@ -335,10 +338,6 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)  	u16 sqcc;  	int i; -	/* avoid accessing cq (dma coherent memory) if not needed */ -	if (!test_and_clear_bit(MLX5E_CQ_HAS_CQES, &cq->flags)) -		return false; -  	sq = container_of(cq, struct mlx5e_sq, cq);  	npkts = 0; @@ -422,10 +421,6 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)  				netif_tx_wake_queue(sq->txq);  				sq->stats.wake++;  	} -	if (i == MLX5E_TX_CQ_POLL_BUDGET) { -		set_bit(MLX5E_CQ_HAS_CQES, &cq->flags); -		return true; -	} -	return false; +	return (i == MLX5E_TX_CQ_POLL_BUDGET);  } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c index 4ac8d716dbdd..66d51a77609e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c @@ -88,7 +88,6 @@ void mlx5e_completion_event(struct mlx5_core_cq *mcq)  {  	struct mlx5e_cq *cq = container_of(mcq, struct mlx5e_cq, mcq); -	set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);  	set_bit(MLX5E_CHANNEL_NAPI_SCHED, &cq->channel->flags);  	barrier();  	napi_schedule(cq->napi); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 23c244a7e5d7..647a3ca2c2a9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -230,6 +230,7 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq)  		case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:  		case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:  			rsn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff; +			rsn |= (eqe->data.qp_srq.type << MLX5_USER_INDEX_LEN);  			mlx5_core_dbg(dev, "event %s(%d) arrived on resource 0x%x\n",  				      eqe_type_str(eqe->type), eqe->type, rsn);  			mlx5_rsc_event(dev, rsn, eqe->type); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 6f68dba8d7ed..bf3446794bd5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -77,6 +77,9 @@  #define KERNEL_NUM_PRIOS 1  #define KENREL_MIN_LEVEL 2 +#define ANCHOR_MAX_FT 1 +#define ANCHOR_NUM_PRIOS 1 +#define ANCHOR_MIN_LEVEL (BY_PASS_MIN_LEVEL + 1)  struct node_caps {  	size_t	arr_sz;  	long	*caps; @@ -92,7 +95,7 @@ static struct init_tree_node {  	int max_ft;  } root_fs = {  	.type = FS_TYPE_NAMESPACE, -	.ar_size = 3, +	.ar_size = 4,  	.children = (struct init_tree_node[]) {  		ADD_PRIO(0, BY_PASS_MIN_LEVEL, 0,  			 FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en), @@ -108,6 +111,8 @@ static struct init_tree_node {  					  FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode),  					  FS_CAP(flow_table_properties_nic_receive.flow_table_modify)),  			 ADD_NS(ADD_MULTIPLE_PRIO(LEFTOVERS_NUM_PRIOS, LEFTOVERS_MAX_FT))), +		ADD_PRIO(0, ANCHOR_MIN_LEVEL, 0, {}, +			 ADD_NS(ADD_MULTIPLE_PRIO(ANCHOR_NUM_PRIOS, ANCHOR_MAX_FT))),  	}  }; @@ -196,8 +201,10 @@ static void tree_put_node(struct fs_node *node)  static int tree_remove_node(struct fs_node *node)  { -	if (atomic_read(&node->refcount) > 1) -		return -EPERM; +	if (atomic_read(&node->refcount) > 1) { +		atomic_dec(&node->refcount); +		return -EEXIST; +	}  	tree_put_node(node);  	return 0;  } @@ -360,6 +367,11 @@ static void del_rule(struct fs_node *node)  	memcpy(match_value, fte->val, sizeof(fte->val));  	fs_get_obj(ft, fg->node.parent);  	list_del(&rule->node.list); +	if (rule->sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) { +		mutex_lock(&rule->dest_attr.ft->lock); +		list_del(&rule->next_ft); +		mutex_unlock(&rule->dest_attr.ft->lock); +	}  	fte->dests_size--;  	if (fte->dests_size) {  		err = mlx5_cmd_update_fte(dev, ft, @@ -465,6 +477,8 @@ static struct mlx5_flow_table *alloc_flow_table(int level, int max_fte,  	ft->node.type = FS_TYPE_FLOW_TABLE;  	ft->type = table_type;  	ft->max_fte = max_fte; +	INIT_LIST_HEAD(&ft->fwd_rules); +	mutex_init(&ft->lock);  	return ft;  } @@ -601,9 +615,63 @@ static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio  	return err;  } +static int mlx5_modify_rule_destination(struct mlx5_flow_rule *rule, +					struct mlx5_flow_destination *dest) +{ +	struct mlx5_flow_table *ft; +	struct mlx5_flow_group *fg; +	struct fs_fte *fte; +	int err = 0; + +	fs_get_obj(fte, rule->node.parent); +	if (!(fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST)) +		return -EINVAL; +	lock_ref_node(&fte->node); +	fs_get_obj(fg, fte->node.parent); +	fs_get_obj(ft, fg->node.parent); + +	memcpy(&rule->dest_attr, dest, sizeof(*dest)); +	err = mlx5_cmd_update_fte(get_dev(&ft->node), +				  ft, fg->id, fte); +	unlock_ref_node(&fte->node); + +	return err; +} + +/* Modify/set FWD rules that point on old_next_ft to point on new_next_ft  */ +static int connect_fwd_rules(struct mlx5_core_dev *dev, +			     struct mlx5_flow_table *new_next_ft, +			     struct mlx5_flow_table *old_next_ft) +{ +	struct mlx5_flow_destination dest; +	struct mlx5_flow_rule *iter; +	int err = 0; + +	/* new_next_ft and old_next_ft could be NULL only +	 * when we create/destroy the anchor flow table. +	 */ +	if (!new_next_ft || !old_next_ft) +		return 0; + +	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; +	dest.ft = new_next_ft; + +	mutex_lock(&old_next_ft->lock); +	list_splice_init(&old_next_ft->fwd_rules, &new_next_ft->fwd_rules); +	mutex_unlock(&old_next_ft->lock); +	list_for_each_entry(iter, &new_next_ft->fwd_rules, next_ft) { +		err = mlx5_modify_rule_destination(iter, &dest); +		if (err) +			pr_err("mlx5_core: failed to modify rule to point on flow table %d\n", +			       new_next_ft->id); +	} +	return 0; +} +  static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *ft,  			      struct fs_prio *prio)  { +	struct mlx5_flow_table *next_ft;  	int err = 0;  	/* Connect_prev_fts and update_root_ft_create are mutually exclusive */ @@ -612,6 +680,11 @@ static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table  		err = connect_prev_fts(dev, ft, prio);  		if (err)  			return err; + +		next_ft = find_next_chained_ft(prio); +		err = connect_fwd_rules(dev, ft, next_ft); +		if (err) +			return err;  	}  	if (MLX5_CAP_FLOWTABLE(dev, @@ -762,6 +835,7 @@ static struct mlx5_flow_rule *alloc_rule(struct mlx5_flow_destination *dest)  	if (!rule)  		return NULL; +	INIT_LIST_HEAD(&rule->next_ft);  	rule->node.type = FS_TYPE_FLOW_DEST;  	memcpy(&rule->dest_attr, dest, sizeof(*dest)); @@ -782,9 +856,14 @@ static struct mlx5_flow_rule *add_rule_fte(struct fs_fte *fte,  		return ERR_PTR(-ENOMEM);  	fs_get_obj(ft, fg->node.parent); -	/* Add dest to dests list- added as first element after the head */ +	/* Add dest to dests list- we need flow tables to be in the +	 * end of the list for forward to next prio rules. +	 */  	tree_init_node(&rule->node, 1, del_rule); -	list_add_tail(&rule->node.list, &fte->node.children); +	if (dest && dest->type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) +		list_add(&rule->node.list, &fte->node.children); +	else +		list_add_tail(&rule->node.list, &fte->node.children);  	fte->dests_size++;  	if (fte->dests_size == 1)  		err = mlx5_cmd_create_fte(get_dev(&ft->node), @@ -903,6 +982,25 @@ out:  	return fg;  } +static struct mlx5_flow_rule *find_flow_rule(struct fs_fte *fte, +					     struct mlx5_flow_destination *dest) +{ +	struct mlx5_flow_rule *rule; + +	list_for_each_entry(rule, &fte->node.children, node.list) { +		if (rule->dest_attr.type == dest->type) { +			if ((dest->type == MLX5_FLOW_DESTINATION_TYPE_VPORT && +			     dest->vport_num == rule->dest_attr.vport_num) || +			    (dest->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE && +			     dest->ft == rule->dest_attr.ft) || +			    (dest->type == MLX5_FLOW_DESTINATION_TYPE_TIR && +			     dest->tir_num == rule->dest_attr.tir_num)) +				return rule; +		} +	} +	return NULL; +} +  static struct mlx5_flow_rule *add_rule_fg(struct mlx5_flow_group *fg,  					  u32 *match_value,  					  u8 action, @@ -919,6 +1017,13 @@ static struct mlx5_flow_rule *add_rule_fg(struct mlx5_flow_group *fg,  		nested_lock_ref_node(&fte->node, FS_MUTEX_CHILD);  		if (compare_match_value(&fg->mask, match_value, &fte->val) &&  		    action == fte->action && flow_tag == fte->flow_tag) { +			rule = find_flow_rule(fte, dest); +			if (rule) { +				atomic_inc(&rule->node.refcount); +				unlock_ref_node(&fte->node); +				unlock_ref_node(&fg->node); +				return rule; +			}  			rule = add_rule_fte(fte, fg, dest);  			unlock_ref_node(&fte->node);  			if (IS_ERR(rule)) @@ -984,14 +1089,14 @@ static struct mlx5_flow_rule *add_rule_to_auto_fg(struct mlx5_flow_table *ft,  	return rule;  } -struct mlx5_flow_rule * -mlx5_add_flow_rule(struct mlx5_flow_table *ft, -		   u8 match_criteria_enable, -		   u32 *match_criteria, -		   u32 *match_value, -		   u32 action, -		   u32 flow_tag, -		   struct mlx5_flow_destination *dest) +static struct mlx5_flow_rule * +_mlx5_add_flow_rule(struct mlx5_flow_table *ft, +		    u8 match_criteria_enable, +		    u32 *match_criteria, +		    u32 *match_value, +		    u32 action, +		    u32 flow_tag, +		    struct mlx5_flow_destination *dest)  {  	struct mlx5_flow_group *g;  	struct mlx5_flow_rule *rule; @@ -1014,6 +1119,63 @@ unlock:  	unlock_ref_node(&ft->node);  	return rule;  } + +static bool fwd_next_prio_supported(struct mlx5_flow_table *ft) +{ +	return ((ft->type == FS_FT_NIC_RX) && +		(MLX5_CAP_FLOWTABLE(get_dev(&ft->node), nic_rx_multi_path_tirs))); +} + +struct mlx5_flow_rule * +mlx5_add_flow_rule(struct mlx5_flow_table *ft, +		   u8 match_criteria_enable, +		   u32 *match_criteria, +		   u32 *match_value, +		   u32 action, +		   u32 flow_tag, +		   struct mlx5_flow_destination *dest) +{ +	struct mlx5_flow_root_namespace *root = find_root(&ft->node); +	struct mlx5_flow_destination gen_dest; +	struct mlx5_flow_table *next_ft = NULL; +	struct mlx5_flow_rule *rule = NULL; +	u32 sw_action = action; +	struct fs_prio *prio; + +	fs_get_obj(prio, ft->node.parent); +	if (action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) { +		if (!fwd_next_prio_supported(ft)) +			return ERR_PTR(-EOPNOTSUPP); +		if (dest) +			return ERR_PTR(-EINVAL); +		mutex_lock(&root->chain_lock); +		next_ft = find_next_chained_ft(prio); +		if (next_ft) { +			gen_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; +			gen_dest.ft = next_ft; +			dest = &gen_dest; +			action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; +		} else { +			mutex_unlock(&root->chain_lock); +			return ERR_PTR(-EOPNOTSUPP); +		} +	} + +	rule =	_mlx5_add_flow_rule(ft, match_criteria_enable, match_criteria, +				    match_value, action, flow_tag, dest); + +	if (sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) { +		if (!IS_ERR_OR_NULL(rule) && +		    (list_empty(&rule->next_ft))) { +			mutex_lock(&next_ft->lock); +			list_add(&rule->next_ft, &next_ft->fwd_rules); +			mutex_unlock(&next_ft->lock); +			rule->sw_action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO; +		} +		mutex_unlock(&root->chain_lock); +	} +	return rule; +}  EXPORT_SYMBOL(mlx5_add_flow_rule);  void mlx5_del_flow_rule(struct mlx5_flow_rule *rule) @@ -1077,6 +1239,10 @@ static int disconnect_flow_table(struct mlx5_flow_table *ft)  		return 0;  	next_ft = find_next_chained_ft(prio); +	err = connect_fwd_rules(dev, next_ft, ft); +	if (err) +		return err; +  	err = connect_prev_fts(dev, next_ft, prio);  	if (err)  		mlx5_core_warn(dev, "Failed to disconnect flow table %d\n", @@ -1126,6 +1292,7 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,  	case MLX5_FLOW_NAMESPACE_BYPASS:  	case MLX5_FLOW_NAMESPACE_KERNEL:  	case MLX5_FLOW_NAMESPACE_LEFTOVERS: +	case MLX5_FLOW_NAMESPACE_ANCHOR:  		prio = type;  		break;  	case MLX5_FLOW_NAMESPACE_FDB: @@ -1351,6 +1518,25 @@ static void set_prio_attrs(struct mlx5_flow_root_namespace *root_ns)  	}  } +#define ANCHOR_PRIO 0 +#define ANCHOR_SIZE 1 +static int create_anchor_flow_table(struct mlx5_core_dev +							*dev) +{ +	struct mlx5_flow_namespace *ns = NULL; +	struct mlx5_flow_table *ft; + +	ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ANCHOR); +	if (!ns) +		return -EINVAL; +	ft = mlx5_create_flow_table(ns, ANCHOR_PRIO, ANCHOR_SIZE); +	if (IS_ERR(ft)) { +		mlx5_core_err(dev, "Failed to create last anchor flow table"); +		return PTR_ERR(ft); +	} +	return 0; +} +  static int init_root_ns(struct mlx5_core_dev *dev)  { @@ -1363,6 +1549,9 @@ static int init_root_ns(struct mlx5_core_dev *dev)  	set_prio_attrs(dev->priv.root_ns); +	if (create_anchor_flow_table(dev)) +		goto cleanup; +  	return 0;  cleanup: @@ -1392,6 +1581,15 @@ static void cleanup_single_prio_root_ns(struct mlx5_core_dev *dev,  	root_ns = NULL;  } +static void destroy_flow_tables(struct fs_prio *prio) +{ +	struct mlx5_flow_table *iter; +	struct mlx5_flow_table *tmp; + +	fs_for_each_ft_safe(iter, tmp, prio) +		mlx5_destroy_flow_table(iter); +} +  static void cleanup_root_ns(struct mlx5_core_dev *dev)  {  	struct mlx5_flow_root_namespace *root_ns = dev->priv.root_ns; @@ -1420,6 +1618,7 @@ static void cleanup_root_ns(struct mlx5_core_dev *dev)  							 list);  				fs_get_obj(obj_iter_prio2, iter_prio2); +				destroy_flow_tables(obj_iter_prio2);  				if (tree_remove_node(iter_prio2)) {  					mlx5_core_warn(dev,  						       "Priority %d wasn't destroyed, refcount > 1\n", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index 00245fd7e4bc..f37a6248a27b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -68,6 +68,11 @@ struct fs_node {  struct mlx5_flow_rule {  	struct fs_node				node;  	struct mlx5_flow_destination		dest_attr; +	/* next_ft should be accessed under chain_lock and only of +	 * destination type is FWD_NEXT_fT. +	 */ +	struct list_head			next_ft; +	u32					sw_action;  };  /* Type of children is mlx5_flow_group */ @@ -82,6 +87,10 @@ struct mlx5_flow_table {  		unsigned int		required_groups;  		unsigned int		num_groups;  	} autogroup; +	/* Protect fwd_rules */ +	struct mutex			lock; +	/* FWD rules that point on this flow table */ +	struct list_head		fwd_rules;  };  /* Type of children is mlx5_flow_rule */ @@ -142,6 +151,9 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev);  #define fs_list_for_each_entry(pos, root)		\  	list_for_each_entry(pos, root, node.list) +#define fs_list_for_each_entry_safe(pos, tmp, root)		\ +	list_for_each_entry_safe(pos, tmp, root, node.list) +  #define fs_for_each_ns_or_ft_reverse(pos, prio)				\  	list_for_each_entry_reverse(pos, &(prio)->node.children, list) @@ -157,6 +169,9 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev);  #define fs_for_each_ft(pos, prio)			\  	fs_list_for_each_entry(pos, &(prio)->node.children) +#define fs_for_each_ft_safe(pos, tmp, prio)			\ +	fs_list_for_each_entry_safe(pos, tmp, &(prio)->node.children) +  #define fs_for_each_fg(pos, ft)			\  	fs_list_for_each_entry(pos, &(ft)->node.children) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index b37749a3730e..0916bbc69269 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -78,6 +78,11 @@ struct mlx5_device_context {  	void		       *context;  }; +enum { +	MLX5_ATOMIC_REQ_MODE_BE = 0x0, +	MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS = 0x1, +}; +  static struct mlx5_profile profile[] = {  	[0] = {  		.mask           = 0, @@ -387,7 +392,7 @@ query_ex:  	return err;  } -static int set_caps(struct mlx5_core_dev *dev, void *in, int in_sz) +static int set_caps(struct mlx5_core_dev *dev, void *in, int in_sz, int opmod)  {  	u32 out[MLX5_ST_SZ_DW(set_hca_cap_out)];  	int err; @@ -395,6 +400,7 @@ static int set_caps(struct mlx5_core_dev *dev, void *in, int in_sz)  	memset(out, 0, sizeof(out));  	MLX5_SET(set_hca_cap_in, in, opcode, MLX5_CMD_OP_SET_HCA_CAP); +	MLX5_SET(set_hca_cap_in, in, op_mod, opmod << 1);  	err = mlx5_cmd_exec(dev, in, in_sz, out, sizeof(out));  	if (err)  		return err; @@ -404,6 +410,46 @@ static int set_caps(struct mlx5_core_dev *dev, void *in, int in_sz)  	return err;  } +static int handle_hca_cap_atomic(struct mlx5_core_dev *dev) +{ +	void *set_ctx; +	void *set_hca_cap; +	int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in); +	int req_endianness; +	int err; + +	if (MLX5_CAP_GEN(dev, atomic)) { +		err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC, +					 HCA_CAP_OPMOD_GET_CUR); +		if (err) +			return err; +	} else { +		return 0; +	} + +	req_endianness = +		MLX5_CAP_ATOMIC(dev, +				supported_atomic_req_8B_endianess_mode_1); + +	if (req_endianness != MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS) +		return 0; + +	set_ctx = kzalloc(set_sz, GFP_KERNEL); +	if (!set_ctx) +		return -ENOMEM; + +	set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability); + +	/* Set requestor to host endianness */ +	MLX5_SET(atomic_caps, set_hca_cap, atomic_req_8B_endianess_mode, +		 MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS); + +	err = set_caps(dev, set_ctx, set_sz, MLX5_SET_HCA_CAP_OP_MOD_ATOMIC); + +	kfree(set_ctx); +	return err; +} +  static int handle_hca_cap(struct mlx5_core_dev *dev)  {  	void *set_ctx = NULL; @@ -445,7 +491,8 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)  	MLX5_SET(cmd_hca_cap, set_hca_cap, log_uar_page_sz, PAGE_SHIFT - 12); -	err = set_caps(dev, set_ctx, set_sz); +	err = set_caps(dev, set_ctx, set_sz, +		       MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE);  query_ex:  	kfree(set_ctx); @@ -667,7 +714,6 @@ clean:  	return err;  } -#ifdef CONFIG_MLX5_CORE_EN  static int mlx5_core_set_issi(struct mlx5_core_dev *dev)  {  	u32 query_in[MLX5_ST_SZ_DW(query_issi_in)]; @@ -720,7 +766,6 @@ static int mlx5_core_set_issi(struct mlx5_core_dev *dev)  	return -ENOTSUPP;  } -#endif  static int map_bf_area(struct mlx5_core_dev *dev)  { @@ -966,13 +1011,11 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)  		goto err_pagealloc_cleanup;  	} -#ifdef CONFIG_MLX5_CORE_EN  	err = mlx5_core_set_issi(dev);  	if (err) {  		dev_err(&pdev->dev, "failed to set issi\n");  		goto err_disable_hca;  	} -#endif  	err = mlx5_satisfy_startup_pages(dev, 1);  	if (err) { @@ -992,6 +1035,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)  		goto reclaim_boot_pages;  	} +	err = handle_hca_cap_atomic(dev); +	if (err) { +		dev_err(&pdev->dev, "handle_hca_cap_atomic failed\n"); +		goto reclaim_boot_pages; +	} +  	err = mlx5_satisfy_startup_pages(dev, 0);  	if (err) {  		dev_err(&pdev->dev, "failed to allocate init pages\n"); @@ -1068,7 +1117,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)  	mlx5_init_cq_table(dev);  	mlx5_init_qp_table(dev);  	mlx5_init_srq_table(dev); -	mlx5_init_mr_table(dev); +	mlx5_init_mkey_table(dev);  	err = mlx5_init_fs(dev);  	if (err) { @@ -1115,7 +1164,7 @@ err_sriov:  err_reg_dev:  	mlx5_cleanup_fs(dev);  err_fs: -	mlx5_cleanup_mr_table(dev); +	mlx5_cleanup_mkey_table(dev);  	mlx5_cleanup_srq_table(dev);  	mlx5_cleanup_qp_table(dev);  	mlx5_cleanup_cq_table(dev); @@ -1188,7 +1237,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)  #endif  	mlx5_cleanup_fs(dev); -	mlx5_cleanup_mr_table(dev); +	mlx5_cleanup_mkey_table(dev);  	mlx5_cleanup_srq_table(dev);  	mlx5_cleanup_qp_table(dev);  	mlx5_cleanup_cq_table(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c index 6fa22b51e460..77a7293921d5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c @@ -36,25 +36,26 @@  #include <linux/mlx5/cmd.h>  #include "mlx5_core.h" -void mlx5_init_mr_table(struct mlx5_core_dev *dev) +void mlx5_init_mkey_table(struct mlx5_core_dev *dev)  { -	struct mlx5_mr_table *table = &dev->priv.mr_table; +	struct mlx5_mkey_table *table = &dev->priv.mkey_table;  	memset(table, 0, sizeof(*table));  	rwlock_init(&table->lock);  	INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);  } -void mlx5_cleanup_mr_table(struct mlx5_core_dev *dev) +void mlx5_cleanup_mkey_table(struct mlx5_core_dev *dev)  {  } -int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, +int mlx5_core_create_mkey(struct mlx5_core_dev *dev, +			  struct mlx5_core_mkey *mkey,  			  struct mlx5_create_mkey_mbox_in *in, int inlen,  			  mlx5_cmd_cbk_t callback, void *context,  			  struct mlx5_create_mkey_mbox_out *out)  { -	struct mlx5_mr_table *table = &dev->priv.mr_table; +	struct mlx5_mkey_table *table = &dev->priv.mkey_table;  	struct mlx5_create_mkey_mbox_out lout;  	int err;  	u8 key; @@ -83,34 +84,35 @@ int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,  		return mlx5_cmd_status_to_err(&lout.hdr);  	} -	mr->iova = be64_to_cpu(in->seg.start_addr); -	mr->size = be64_to_cpu(in->seg.len); -	mr->key = mlx5_idx_to_mkey(be32_to_cpu(lout.mkey) & 0xffffff) | key; -	mr->pd = be32_to_cpu(in->seg.flags_pd) & 0xffffff; +	mkey->iova = be64_to_cpu(in->seg.start_addr); +	mkey->size = be64_to_cpu(in->seg.len); +	mkey->key = mlx5_idx_to_mkey(be32_to_cpu(lout.mkey) & 0xffffff) | key; +	mkey->pd = be32_to_cpu(in->seg.flags_pd) & 0xffffff;  	mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", -		      be32_to_cpu(lout.mkey), key, mr->key); +		      be32_to_cpu(lout.mkey), key, mkey->key); -	/* connect to MR tree */ +	/* connect to mkey tree */  	write_lock_irq(&table->lock); -	err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->key), mr); +	err = radix_tree_insert(&table->tree, mlx5_base_mkey(mkey->key), mkey);  	write_unlock_irq(&table->lock);  	if (err) { -		mlx5_core_warn(dev, "failed radix tree insert of mr 0x%x, %d\n", -			       mlx5_base_mkey(mr->key), err); -		mlx5_core_destroy_mkey(dev, mr); +		mlx5_core_warn(dev, "failed radix tree insert of mkey 0x%x, %d\n", +			       mlx5_base_mkey(mkey->key), err); +		mlx5_core_destroy_mkey(dev, mkey);  	}  	return err;  }  EXPORT_SYMBOL(mlx5_core_create_mkey); -int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr) +int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, +			   struct mlx5_core_mkey *mkey)  { -	struct mlx5_mr_table *table = &dev->priv.mr_table; +	struct mlx5_mkey_table *table = &dev->priv.mkey_table;  	struct mlx5_destroy_mkey_mbox_in in;  	struct mlx5_destroy_mkey_mbox_out out; -	struct mlx5_core_mr *deleted_mr; +	struct mlx5_core_mkey *deleted_mkey;  	unsigned long flags;  	int err; @@ -118,16 +120,16 @@ int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)  	memset(&out, 0, sizeof(out));  	write_lock_irqsave(&table->lock, flags); -	deleted_mr = radix_tree_delete(&table->tree, mlx5_base_mkey(mr->key)); +	deleted_mkey = radix_tree_delete(&table->tree, mlx5_base_mkey(mkey->key));  	write_unlock_irqrestore(&table->lock, flags); -	if (!deleted_mr) { -		mlx5_core_warn(dev, "failed radix tree delete of mr 0x%x\n", -			       mlx5_base_mkey(mr->key)); +	if (!deleted_mkey) { +		mlx5_core_warn(dev, "failed radix tree delete of mkey 0x%x\n", +			       mlx5_base_mkey(mkey->key));  		return -ENOENT;  	}  	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_MKEY); -	in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key)); +	in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mkey->key));  	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));  	if (err)  		return err; @@ -139,7 +141,7 @@ int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)  }  EXPORT_SYMBOL(mlx5_core_destroy_mkey); -int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, +int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mkey *mkey,  			 struct mlx5_query_mkey_mbox_out *out, int outlen)  {  	struct mlx5_query_mkey_mbox_in in; @@ -149,7 +151,7 @@ int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,  	memset(out, 0, outlen);  	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_MKEY); -	in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key)); +	in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mkey->key));  	err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);  	if (err)  		return err; @@ -161,7 +163,7 @@ int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,  }  EXPORT_SYMBOL(mlx5_core_query_mkey); -int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, +int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mkey *_mkey,  			     u32 *mkey)  {  	struct mlx5_query_special_ctxs_mbox_in in; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index a87e773e93f3..5635ce7ad693 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -324,6 +324,29 @@ int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,  }  EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap); +int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, +			     u8 port_num, void *out, size_t sz) +{ +	u32 *in; +	int err; + +	in  = mlx5_vzalloc(sz); +	if (!in) { +		err = -ENOMEM; +		return err; +	} + +	MLX5_SET(ppcnt_reg, in, local_port, port_num); + +	MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP); +	err = mlx5_core_access_reg(dev, in, sz, out, +				   sz, MLX5_REG_PPCNT, 0, 0); + +	kvfree(in); +	return err; +} +EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt); +  int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)  {  	u32 in[MLX5_ST_SZ_DW(pfcc_reg)]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 30e2ba3f5f16..def289375ecb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -36,6 +36,7 @@  #include <linux/mlx5/cmd.h>  #include <linux/mlx5/qp.h>  #include <linux/mlx5/driver.h> +#include <linux/mlx5/transobj.h>  #include "mlx5_core.h" @@ -67,6 +68,52 @@ void mlx5_core_put_rsc(struct mlx5_core_rsc_common *common)  		complete(&common->free);  } +static u64 qp_allowed_event_types(void) +{ +	u64 mask; + +	mask = BIT(MLX5_EVENT_TYPE_PATH_MIG) | +	       BIT(MLX5_EVENT_TYPE_COMM_EST) | +	       BIT(MLX5_EVENT_TYPE_SQ_DRAINED) | +	       BIT(MLX5_EVENT_TYPE_SRQ_LAST_WQE) | +	       BIT(MLX5_EVENT_TYPE_WQ_CATAS_ERROR) | +	       BIT(MLX5_EVENT_TYPE_PATH_MIG_FAILED) | +	       BIT(MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | +	       BIT(MLX5_EVENT_TYPE_WQ_ACCESS_ERROR); + +	return mask; +} + +static u64 rq_allowed_event_types(void) +{ +	u64 mask; + +	mask = BIT(MLX5_EVENT_TYPE_SRQ_LAST_WQE) | +	       BIT(MLX5_EVENT_TYPE_WQ_CATAS_ERROR); + +	return mask; +} + +static u64 sq_allowed_event_types(void) +{ +	return BIT(MLX5_EVENT_TYPE_WQ_CATAS_ERROR); +} + +static bool is_event_type_allowed(int rsc_type, int event_type) +{ +	switch (rsc_type) { +	case MLX5_EVENT_QUEUE_TYPE_QP: +		return BIT(event_type) & qp_allowed_event_types(); +	case MLX5_EVENT_QUEUE_TYPE_RQ: +		return BIT(event_type) & rq_allowed_event_types(); +	case MLX5_EVENT_QUEUE_TYPE_SQ: +		return BIT(event_type) & sq_allowed_event_types(); +	default: +		WARN(1, "Event arrived for unknown resource type"); +		return false; +	} +} +  void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type)  {  	struct mlx5_core_rsc_common *common = mlx5_get_rsc(dev, rsn); @@ -75,8 +122,16 @@ void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type)  	if (!common)  		return; +	if (!is_event_type_allowed((rsn >> MLX5_USER_INDEX_LEN), event_type)) { +		mlx5_core_warn(dev, "event 0x%.2x is not allowed on resource 0x%.8x\n", +			       event_type, rsn); +		return; +	} +  	switch (common->res) {  	case MLX5_RES_QP: +	case MLX5_RES_RQ: +	case MLX5_RES_SQ:  		qp = (struct mlx5_core_qp *)common;  		qp->event(qp, event_type);  		break; @@ -177,27 +232,56 @@ void mlx5_eq_pagefault(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)  }  #endif +static int create_qprqsq_common(struct mlx5_core_dev *dev, +				struct mlx5_core_qp *qp, +				int rsc_type) +{ +	struct mlx5_qp_table *table = &dev->priv.qp_table; +	int err; + +	qp->common.res = rsc_type; +	spin_lock_irq(&table->lock); +	err = radix_tree_insert(&table->tree, +				qp->qpn | (rsc_type << MLX5_USER_INDEX_LEN), +				qp); +	spin_unlock_irq(&table->lock); +	if (err) +		return err; + +	atomic_set(&qp->common.refcount, 1); +	init_completion(&qp->common.free); +	qp->pid = current->pid; + +	return 0; +} + +static void destroy_qprqsq_common(struct mlx5_core_dev *dev, +				  struct mlx5_core_qp *qp) +{ +	struct mlx5_qp_table *table = &dev->priv.qp_table; +	unsigned long flags; + +	spin_lock_irqsave(&table->lock, flags); +	radix_tree_delete(&table->tree, +			  qp->qpn | (qp->common.res << MLX5_USER_INDEX_LEN)); +	spin_unlock_irqrestore(&table->lock, flags); +	mlx5_core_put_rsc((struct mlx5_core_rsc_common *)qp); +	wait_for_completion(&qp->common.free); +} +  int mlx5_core_create_qp(struct mlx5_core_dev *dev,  			struct mlx5_core_qp *qp,  			struct mlx5_create_qp_mbox_in *in,  			int inlen)  { -	struct mlx5_qp_table *table = &dev->priv.qp_table;  	struct mlx5_create_qp_mbox_out out;  	struct mlx5_destroy_qp_mbox_in din;  	struct mlx5_destroy_qp_mbox_out dout;  	int err; -	void *qpc;  	memset(&out, 0, sizeof(out));  	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_QP); -	if (dev->issi) { -		qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); -		/* 0xffffff means we ask to work with cqe version 0 */ -		MLX5_SET(qpc, qpc, user_index, 0xffffff); -	} -  	err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));  	if (err) {  		mlx5_core_warn(dev, "ret %d\n", err); @@ -213,24 +297,16 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev,  	qp->qpn = be32_to_cpu(out.qpn) & 0xffffff;  	mlx5_core_dbg(dev, "qpn = 0x%x\n", qp->qpn); -	qp->common.res = MLX5_RES_QP; -	spin_lock_irq(&table->lock); -	err = radix_tree_insert(&table->tree, qp->qpn, qp); -	spin_unlock_irq(&table->lock); -	if (err) { -		mlx5_core_warn(dev, "err %d\n", err); +	err = create_qprqsq_common(dev, qp, MLX5_RES_QP); +	if (err)  		goto err_cmd; -	}  	err = mlx5_debug_qp_add(dev, qp);  	if (err)  		mlx5_core_dbg(dev, "failed adding QP 0x%x to debug file system\n",  			      qp->qpn); -	qp->pid = current->pid; -	atomic_set(&qp->common.refcount, 1);  	atomic_inc(&dev->num_qps); -	init_completion(&qp->common.free);  	return 0; @@ -250,18 +326,11 @@ int mlx5_core_destroy_qp(struct mlx5_core_dev *dev,  {  	struct mlx5_destroy_qp_mbox_in in;  	struct mlx5_destroy_qp_mbox_out out; -	struct mlx5_qp_table *table = &dev->priv.qp_table; -	unsigned long flags;  	int err;  	mlx5_debug_qp_remove(dev, qp); -	spin_lock_irqsave(&table->lock, flags); -	radix_tree_delete(&table->tree, qp->qpn); -	spin_unlock_irqrestore(&table->lock, flags); - -	mlx5_core_put_rsc((struct mlx5_core_rsc_common *)qp); -	wait_for_completion(&qp->common.free); +	destroy_qprqsq_common(dev, qp);  	memset(&in, 0, sizeof(in));  	memset(&out, 0, sizeof(out)); @@ -279,59 +348,15 @@ int mlx5_core_destroy_qp(struct mlx5_core_dev *dev,  }  EXPORT_SYMBOL_GPL(mlx5_core_destroy_qp); -int mlx5_core_qp_modify(struct mlx5_core_dev *dev, enum mlx5_qp_state cur_state, -			enum mlx5_qp_state new_state, +int mlx5_core_qp_modify(struct mlx5_core_dev *dev, u16 operation,  			struct mlx5_modify_qp_mbox_in *in, int sqd_event,  			struct mlx5_core_qp *qp)  { -	static const u16 optab[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE] = { -		[MLX5_QP_STATE_RST] = { -			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP, -			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP, -			[MLX5_QP_STATE_INIT]	= MLX5_CMD_OP_RST2INIT_QP, -		}, -		[MLX5_QP_STATE_INIT]  = { -			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP, -			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP, -			[MLX5_QP_STATE_INIT]	= MLX5_CMD_OP_INIT2INIT_QP, -			[MLX5_QP_STATE_RTR]	= MLX5_CMD_OP_INIT2RTR_QP, -		}, -		[MLX5_QP_STATE_RTR]   = { -			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP, -			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP, -			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_RTR2RTS_QP, -		}, -		[MLX5_QP_STATE_RTS]   = { -			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP, -			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP, -			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_RTS2RTS_QP, -		}, -		[MLX5_QP_STATE_SQD] = { -			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP, -			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP, -		}, -		[MLX5_QP_STATE_SQER] = { -			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP, -			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP, -			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_SQERR2RTS_QP, -		}, -		[MLX5_QP_STATE_ERR] = { -			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP, -			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP, -		} -	}; -  	struct mlx5_modify_qp_mbox_out out;  	int err = 0; -	u16 op; - -	if (cur_state >= MLX5_QP_NUM_STATE || new_state >= MLX5_QP_NUM_STATE || -	    !optab[cur_state][new_state]) -		return -EINVAL;  	memset(&out, 0, sizeof(out)); -	op = optab[cur_state][new_state]; -	in->hdr.opcode = cpu_to_be16(op); +	in->hdr.opcode = cpu_to_be16(operation);  	in->qpn = cpu_to_be32(qp->qpn);  	err = mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out));  	if (err) @@ -449,3 +474,67 @@ int mlx5_core_page_fault_resume(struct mlx5_core_dev *dev, u32 qpn,  }  EXPORT_SYMBOL_GPL(mlx5_core_page_fault_resume);  #endif + +int mlx5_core_create_rq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen, +				struct mlx5_core_qp *rq) +{ +	int err; +	u32 rqn; + +	err = mlx5_core_create_rq(dev, in, inlen, &rqn); +	if (err) +		return err; + +	rq->qpn = rqn; +	err = create_qprqsq_common(dev, rq, MLX5_RES_RQ); +	if (err) +		goto err_destroy_rq; + +	return 0; + +err_destroy_rq: +	mlx5_core_destroy_rq(dev, rq->qpn); + +	return err; +} +EXPORT_SYMBOL(mlx5_core_create_rq_tracked); + +void mlx5_core_destroy_rq_tracked(struct mlx5_core_dev *dev, +				  struct mlx5_core_qp *rq) +{ +	destroy_qprqsq_common(dev, rq); +	mlx5_core_destroy_rq(dev, rq->qpn); +} +EXPORT_SYMBOL(mlx5_core_destroy_rq_tracked); + +int mlx5_core_create_sq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen, +				struct mlx5_core_qp *sq) +{ +	int err; +	u32 sqn; + +	err = mlx5_core_create_sq(dev, in, inlen, &sqn); +	if (err) +		return err; + +	sq->qpn = sqn; +	err = create_qprqsq_common(dev, sq, MLX5_RES_SQ); +	if (err) +		goto err_destroy_sq; + +	return 0; + +err_destroy_sq: +	mlx5_core_destroy_sq(dev, sq->qpn); + +	return err; +} +EXPORT_SYMBOL(mlx5_core_create_sq_tracked); + +void mlx5_core_destroy_sq_tracked(struct mlx5_core_dev *dev, +				  struct mlx5_core_qp *sq) +{ +	destroy_qprqsq_common(dev, sq); +	mlx5_core_destroy_sq(dev, sq->qpn); +} +EXPORT_SYMBOL(mlx5_core_destroy_sq_tracked); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c index ffada801976b..04bc522605a0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c @@ -37,7 +37,7 @@  #include <linux/mlx5/srq.h>  #include <rdma/ib_verbs.h>  #include "mlx5_core.h" -#include "transobj.h" +#include <linux/mlx5/transobj.h>  void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type)  { @@ -241,8 +241,6 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev,  	memcpy(xrc_srqc, srqc, MLX5_ST_SZ_BYTES(srqc));  	memcpy(pas, in->pas, pas_size); -	/* 0xffffff means we ask to work with cqe version 0 */ -	MLX5_SET(xrc_srqc,	    xrc_srqc,  user_index, 0xffffff);  	MLX5_SET(create_xrc_srq_in, create_in, opcode,  		 MLX5_CMD_OP_CREATE_XRC_SRQ); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c index d7068f54e800..03a5093ffeb7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c @@ -32,9 +32,9 @@  #include <linux/mlx5/driver.h>  #include "mlx5_core.h" -#include "transobj.h" +#include <linux/mlx5/transobj.h> -int mlx5_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn) +int mlx5_core_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn)  {  	u32 in[MLX5_ST_SZ_DW(alloc_transport_domain_in)];  	u32 out[MLX5_ST_SZ_DW(alloc_transport_domain_out)]; @@ -53,8 +53,9 @@ int mlx5_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn)  	return err;  } +EXPORT_SYMBOL(mlx5_core_alloc_transport_domain); -void mlx5_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn) +void mlx5_core_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn)  {  	u32 in[MLX5_ST_SZ_DW(dealloc_transport_domain_in)];  	u32 out[MLX5_ST_SZ_DW(dealloc_transport_domain_out)]; @@ -68,6 +69,7 @@ void mlx5_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn)  	mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));  } +EXPORT_SYMBOL(mlx5_core_dealloc_transport_domain);  int mlx5_core_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqn)  { @@ -94,6 +96,7 @@ int mlx5_core_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen)  	memset(out, 0, sizeof(out));  	return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));  } +EXPORT_SYMBOL(mlx5_core_modify_rq);  void mlx5_core_destroy_rq(struct mlx5_core_dev *dev, u32 rqn)  { @@ -108,6 +111,18 @@ void mlx5_core_destroy_rq(struct mlx5_core_dev *dev, u32 rqn)  	mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));  } +int mlx5_core_query_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *out) +{ +	u32 in[MLX5_ST_SZ_DW(query_rq_in)] = {0}; +	int outlen = MLX5_ST_SZ_BYTES(query_rq_out); + +	MLX5_SET(query_rq_in, in, opcode, MLX5_CMD_OP_QUERY_RQ); +	MLX5_SET(query_rq_in, in, rqn, rqn); + +	return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, outlen); +} +EXPORT_SYMBOL(mlx5_core_query_rq); +  int mlx5_core_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *sqn)  {  	u32 out[MLX5_ST_SZ_DW(create_sq_out)]; @@ -133,6 +148,7 @@ int mlx5_core_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen)  	memset(out, 0, sizeof(out));  	return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));  } +EXPORT_SYMBOL(mlx5_core_modify_sq);  void mlx5_core_destroy_sq(struct mlx5_core_dev *dev, u32 sqn)  { @@ -147,6 +163,18 @@ void mlx5_core_destroy_sq(struct mlx5_core_dev *dev, u32 sqn)  	mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));  } +int mlx5_core_query_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *out) +{ +	u32 in[MLX5_ST_SZ_DW(query_sq_in)] = {0}; +	int outlen = MLX5_ST_SZ_BYTES(query_sq_out); + +	MLX5_SET(query_sq_in, in, opcode, MLX5_CMD_OP_QUERY_SQ); +	MLX5_SET(query_sq_in, in, sqn, sqn); + +	return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, outlen); +} +EXPORT_SYMBOL(mlx5_core_query_sq); +  int mlx5_core_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen,  			 u32 *tirn)  { @@ -162,6 +190,7 @@ int mlx5_core_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen,  	return err;  } +EXPORT_SYMBOL(mlx5_core_create_tir);  int mlx5_core_modify_tir(struct mlx5_core_dev *dev, u32 tirn, u32 *in,  			 int inlen) @@ -187,6 +216,7 @@ void mlx5_core_destroy_tir(struct mlx5_core_dev *dev, u32 tirn)  	mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));  } +EXPORT_SYMBOL(mlx5_core_destroy_tir);  int mlx5_core_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen,  			 u32 *tisn) @@ -203,6 +233,19 @@ int mlx5_core_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen,  	return err;  } +EXPORT_SYMBOL(mlx5_core_create_tis); + +int mlx5_core_modify_tis(struct mlx5_core_dev *dev, u32 tisn, u32 *in, +			 int inlen) +{ +	u32 out[MLX5_ST_SZ_DW(modify_tis_out)] = {0}; + +	MLX5_SET(modify_tis_in, in, tisn, tisn); +	MLX5_SET(modify_tis_in, in, opcode, MLX5_CMD_OP_MODIFY_TIS); + +	return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); +} +EXPORT_SYMBOL(mlx5_core_modify_tis);  void mlx5_core_destroy_tis(struct mlx5_core_dev *dev, u32 tisn)  { @@ -216,6 +259,7 @@ void mlx5_core_destroy_tis(struct mlx5_core_dev *dev, u32 tisn)  	mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));  } +EXPORT_SYMBOL(mlx5_core_destroy_tis);  int mlx5_core_create_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen,  			 u32 *rmpn) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h deleted file mode 100644 index 74cae51436e4..000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2013-2015, Mellanox Technologies, Ltd.  All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses.  You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - *     Redistribution and use in source and binary forms, with or - *     without modification, are permitted provided that the following - *     conditions are met: - * - *      - Redistributions of source code must retain the above - *        copyright notice, this list of conditions and the following - *        disclaimer. - * - *      - Redistributions in binary form must reproduce the above - *        copyright notice, this list of conditions and the following - *        disclaimer in the documentation and/or other materials - *        provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __TRANSOBJ_H__ -#define __TRANSOBJ_H__ - -int mlx5_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn); -void mlx5_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn); -int mlx5_core_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, -			u32 *rqn); -int mlx5_core_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen); -void mlx5_core_destroy_rq(struct mlx5_core_dev *dev, u32 rqn); -int mlx5_core_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen, -			u32 *sqn); -int mlx5_core_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen); -void mlx5_core_destroy_sq(struct mlx5_core_dev *dev, u32 sqn); -int mlx5_core_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen, -			 u32 *tirn); -int mlx5_core_modify_tir(struct mlx5_core_dev *dev, u32 tirn, u32 *in, -			 int inlen); -void mlx5_core_destroy_tir(struct mlx5_core_dev *dev, u32 tirn); -int mlx5_core_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen, -			 u32 *tisn); -void mlx5_core_destroy_tis(struct mlx5_core_dev *dev, u32 tisn); -int mlx5_core_create_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen, -			 u32 *rmpn); -int mlx5_core_modify_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen); -int mlx5_core_destroy_rmp(struct mlx5_core_dev *dev, u32 rmpn); -int mlx5_core_query_rmp(struct mlx5_core_dev *dev, u32 rmpn, u32 *out); -int mlx5_core_arm_rmp(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm); -int mlx5_core_create_xsrq(struct mlx5_core_dev *dev, u32 *in, int inlen, -			  u32 *rmpn); -int mlx5_core_destroy_xsrq(struct mlx5_core_dev *dev, u32 rmpn); -int mlx5_core_query_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u32 *out); -int mlx5_core_arm_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm); - -int mlx5_core_create_rqt(struct mlx5_core_dev *dev, u32 *in, int inlen, -			 u32 *rqtn); -int mlx5_core_modify_rqt(struct mlx5_core_dev *dev, u32 rqtn, u32 *in, -			 int inlen); -void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn); - -#endif /* __TRANSOBJ_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 076197efea9b..90ab09e375b8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -76,7 +76,7 @@ u8 mlx5_query_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport)  	return MLX5_GET(query_vport_state_out, out, admin_state);  } -EXPORT_SYMBOL(mlx5_query_vport_admin_state); +EXPORT_SYMBOL_GPL(mlx5_query_vport_admin_state);  int mlx5_modify_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod,  				  u16 vport, u8 state) @@ -104,7 +104,7 @@ int mlx5_modify_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod,  	return err;  } -EXPORT_SYMBOL(mlx5_modify_vport_admin_state); +EXPORT_SYMBOL_GPL(mlx5_modify_vport_admin_state);  static int mlx5_query_nic_vport_context(struct mlx5_core_dev *mdev, u16 vport,  					u32 *out, int outlen) @@ -151,12 +151,9 @@ int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev,  				nic_vport_context.permanent_address);  	err = mlx5_query_nic_vport_context(mdev, vport, out, outlen); -	if (err) -		goto out; - -	ether_addr_copy(addr, &out_addr[2]); +	if (!err) +		ether_addr_copy(addr, &out_addr[2]); -out:  	kvfree(out);  	return err;  } @@ -197,7 +194,7 @@ int mlx5_modify_nic_vport_mac_address(struct mlx5_core_dev *mdev,  	return err;  } -EXPORT_SYMBOL(mlx5_modify_nic_vport_mac_address); +EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_mac_address);  int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,  				  u32 vport, @@ -430,6 +427,68 @@ int mlx5_modify_nic_vport_vlans(struct mlx5_core_dev *dev,  }  EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_vlans); +int mlx5_query_nic_vport_system_image_guid(struct mlx5_core_dev *mdev, +					   u64 *system_image_guid) +{ +	u32 *out; +	int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); + +	out = mlx5_vzalloc(outlen); +	if (!out) +		return -ENOMEM; + +	mlx5_query_nic_vport_context(mdev, 0, out, outlen); + +	*system_image_guid = MLX5_GET64(query_nic_vport_context_out, out, +					nic_vport_context.system_image_guid); + +	kfree(out); + +	return 0; +} +EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_system_image_guid); + +int mlx5_query_nic_vport_node_guid(struct mlx5_core_dev *mdev, u64 *node_guid) +{ +	u32 *out; +	int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); + +	out = mlx5_vzalloc(outlen); +	if (!out) +		return -ENOMEM; + +	mlx5_query_nic_vport_context(mdev, 0, out, outlen); + +	*node_guid = MLX5_GET64(query_nic_vport_context_out, out, +				nic_vport_context.node_guid); + +	kfree(out); + +	return 0; +} +EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_node_guid); + +int mlx5_query_nic_vport_qkey_viol_cntr(struct mlx5_core_dev *mdev, +					u16 *qkey_viol_cntr) +{ +	u32 *out; +	int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); + +	out = mlx5_vzalloc(outlen); +	if (!out) +		return -ENOMEM; + +	mlx5_query_nic_vport_context(mdev, 0, out, outlen); + +	*qkey_viol_cntr = MLX5_GET(query_nic_vport_context_out, out, +				   nic_vport_context.qkey_violation_counter); + +	kfree(out); + +	return 0; +} +EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_qkey_viol_cntr); +  int mlx5_query_hca_vport_gid(struct mlx5_core_dev *dev, u8 other_vport,  			     u8 port_num, u16  vf_num, u16 gid_index,  			     union ib_gid *gid) @@ -750,3 +809,84 @@ int mlx5_modify_nic_vport_promisc(struct mlx5_core_dev *mdev,  	return err;  }  EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_promisc); + +enum mlx5_vport_roce_state { +	MLX5_VPORT_ROCE_DISABLED = 0, +	MLX5_VPORT_ROCE_ENABLED  = 1, +}; + +static int mlx5_nic_vport_update_roce_state(struct mlx5_core_dev *mdev, +					    enum mlx5_vport_roce_state state) +{ +	void *in; +	int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); +	int err; + +	in = mlx5_vzalloc(inlen); +	if (!in) { +		mlx5_core_warn(mdev, "failed to allocate inbox\n"); +		return -ENOMEM; +	} + +	MLX5_SET(modify_nic_vport_context_in, in, field_select.roce_en, 1); +	MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.roce_en, +		 state); + +	err = mlx5_modify_nic_vport_context(mdev, in, inlen); + +	kvfree(in); + +	return err; +} + +int mlx5_nic_vport_enable_roce(struct mlx5_core_dev *mdev) +{ +	return mlx5_nic_vport_update_roce_state(mdev, MLX5_VPORT_ROCE_ENABLED); +} +EXPORT_SYMBOL_GPL(mlx5_nic_vport_enable_roce); + +int mlx5_nic_vport_disable_roce(struct mlx5_core_dev *mdev) +{ +	return mlx5_nic_vport_update_roce_state(mdev, MLX5_VPORT_ROCE_DISABLED); +} +EXPORT_SYMBOL_GPL(mlx5_nic_vport_disable_roce); + +int mlx5_core_query_vport_counter(struct mlx5_core_dev *dev, u8 other_vport, +				  u8 port_num, void *out, size_t out_sz) +{ +	int	in_sz = MLX5_ST_SZ_BYTES(query_vport_counter_in); +	int	is_group_manager; +	void   *in; +	int	err; + +	is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager); +	in = mlx5_vzalloc(in_sz); +	if (!in) { +		err = -ENOMEM; +		return err; +	} + +	MLX5_SET(query_vport_counter_in, in, opcode, +		 MLX5_CMD_OP_QUERY_VPORT_COUNTER); +	if (other_vport) { +		if (is_group_manager) { +			MLX5_SET(query_vport_counter_in, in, other_vport, 1); +			MLX5_SET(query_vport_counter_in, in, vport_number, 0); +		} else { +			err = -EPERM; +			goto free; +		} +	} +	if (MLX5_CAP_GEN(dev, num_ports) == 2) +		MLX5_SET(query_vport_counter_in, in, port_num, port_num); + +	err = mlx5_cmd_exec(dev, in, in_sz, out,  out_sz); +	if (err) +		goto free; +	err = mlx5_cmd_status_to_err_v2(out); + +free: +	kvfree(in); +	return err; +} +EXPORT_SYMBOL_GPL(mlx5_core_query_vport_counter); diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index c071077aafbd..7992c553c1f5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -215,7 +215,7 @@ mlxsw_pci_queue_elem_info_producer_get(struct mlxsw_pci_queue *q)  {  	int index = q->producer_counter & (q->count - 1); -	if ((q->producer_counter - q->consumer_counter) == q->count) +	if ((u16) (q->producer_counter - q->consumer_counter) == q->count)  		return NULL;  	return mlxsw_pci_queue_elem_info_get(q, index);  } diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h index 726f5435b32f..ae65b9940aed 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/port.h +++ b/drivers/net/ethernet/mellanox/mlxsw/port.h @@ -49,7 +49,7 @@  #define MLXSW_PORT_MID			0xd000  #define MLXSW_PORT_MAX_PHY_PORTS	0x40 -#define MLXSW_PORT_MAX_PORTS		MLXSW_PORT_MAX_PHY_PORTS +#define MLXSW_PORT_MAX_PORTS		(MLXSW_PORT_MAX_PHY_PORTS + 1)  #define MLXSW_PORT_DEVID_BITS_OFFSET	10  #define MLXSW_PORT_PHY_BITS_OFFSET	4 diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 0c5237264e3e..ffe4c0305733 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -873,6 +873,62 @@ static inline void mlxsw_reg_spvm_pack(char *payload, u8 local_port,  	}  } +/* SPAFT - Switch Port Acceptable Frame Types + * ------------------------------------------ + * The Switch Port Acceptable Frame Types register configures the frame + * admittance of the port. + */ +#define MLXSW_REG_SPAFT_ID 0x2010 +#define MLXSW_REG_SPAFT_LEN 0x08 + +static const struct mlxsw_reg_info mlxsw_reg_spaft = { +	.id = MLXSW_REG_SPAFT_ID, +	.len = MLXSW_REG_SPAFT_LEN, +}; + +/* reg_spaft_local_port + * Local port number. + * Access: Index + * + * Note: CPU port is not supported (all tag types are allowed). + */ +MLXSW_ITEM32(reg, spaft, local_port, 0x00, 16, 8); + +/* reg_spaft_sub_port + * Virtual port within the physical port. + * Should be set to 0 when virtual ports are not enabled on the port. + * Access: RW + */ +MLXSW_ITEM32(reg, spaft, sub_port, 0x00, 8, 8); + +/* reg_spaft_allow_untagged + * When set, untagged frames on the ingress are allowed (default). + * Access: RW + */ +MLXSW_ITEM32(reg, spaft, allow_untagged, 0x04, 31, 1); + +/* reg_spaft_allow_prio_tagged + * When set, priority tagged frames on the ingress are allowed (default). + * Access: RW + */ +MLXSW_ITEM32(reg, spaft, allow_prio_tagged, 0x04, 30, 1); + +/* reg_spaft_allow_tagged + * When set, tagged frames on the ingress are allowed (default). + * Access: RW + */ +MLXSW_ITEM32(reg, spaft, allow_tagged, 0x04, 29, 1); + +static inline void mlxsw_reg_spaft_pack(char *payload, u8 local_port, +					bool allow_untagged) +{ +	MLXSW_REG_ZERO(spaft, payload); +	mlxsw_reg_spaft_local_port_set(payload, local_port); +	mlxsw_reg_spaft_allow_untagged_set(payload, allow_untagged); +	mlxsw_reg_spaft_allow_prio_tagged_set(payload, true); +	mlxsw_reg_spaft_allow_tagged_set(payload, true); +} +  /* SFGC - Switch Flooding Group Configuration   * ------------------------------------------   * The following register controls the association of flooding tables and MIDs @@ -1044,6 +1100,92 @@ static inline void mlxsw_reg_sftr_pack(char *payload,  	mlxsw_reg_sftr_port_mask_set(payload, port, 1);  } +/* SFDF - Switch Filtering DB Flush + * -------------------------------- + * The switch filtering DB flush register is used to flush the FDB. + * Note that FDB notifications are flushed as well. + */ +#define MLXSW_REG_SFDF_ID 0x2013 +#define MLXSW_REG_SFDF_LEN 0x14 + +static const struct mlxsw_reg_info mlxsw_reg_sfdf = { +	.id = MLXSW_REG_SFDF_ID, +	.len = MLXSW_REG_SFDF_LEN, +}; + +/* reg_sfdf_swid + * Switch partition ID. + * Access: Index + */ +MLXSW_ITEM32(reg, sfdf, swid, 0x00, 24, 8); + +enum mlxsw_reg_sfdf_flush_type { +	MLXSW_REG_SFDF_FLUSH_PER_SWID, +	MLXSW_REG_SFDF_FLUSH_PER_FID, +	MLXSW_REG_SFDF_FLUSH_PER_PORT, +	MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID, +	MLXSW_REG_SFDF_FLUSH_PER_LAG, +	MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID, +}; + +/* reg_sfdf_flush_type + * Flush type. + * 0 - All SWID dynamic entries are flushed. + * 1 - All FID dynamic entries are flushed. + * 2 - All dynamic entries pointing to port are flushed. + * 3 - All FID dynamic entries pointing to port are flushed. + * 4 - All dynamic entries pointing to LAG are flushed. + * 5 - All FID dynamic entries pointing to LAG are flushed. + * Access: RW + */ +MLXSW_ITEM32(reg, sfdf, flush_type, 0x04, 28, 4); + +/* reg_sfdf_flush_static + * Static. + * 0 - Flush only dynamic entries. + * 1 - Flush both dynamic and static entries. + * Access: RW + */ +MLXSW_ITEM32(reg, sfdf, flush_static, 0x04, 24, 1); + +static inline void mlxsw_reg_sfdf_pack(char *payload, +				       enum mlxsw_reg_sfdf_flush_type type) +{ +	MLXSW_REG_ZERO(sfdf, payload); +	mlxsw_reg_sfdf_flush_type_set(payload, type); +	mlxsw_reg_sfdf_flush_static_set(payload, true); +} + +/* reg_sfdf_fid + * FID to flush. + * Access: RW + */ +MLXSW_ITEM32(reg, sfdf, fid, 0x0C, 0, 16); + +/* reg_sfdf_system_port + * Port to flush. + * Access: RW + */ +MLXSW_ITEM32(reg, sfdf, system_port, 0x0C, 0, 16); + +/* reg_sfdf_port_fid_system_port + * Port to flush, pointed to by FID. + * Access: RW + */ +MLXSW_ITEM32(reg, sfdf, port_fid_system_port, 0x08, 0, 16); + +/* reg_sfdf_lag_id + * LAG ID to flush. + * Access: RW + */ +MLXSW_ITEM32(reg, sfdf, lag_id, 0x0C, 0, 10); + +/* reg_sfdf_lag_fid_lag_id + * LAG ID to flush, pointed to by FID. + * Access: RW + */ +MLXSW_ITEM32(reg, sfdf, lag_fid_lag_id, 0x08, 0, 10); +  /* SLDR - Switch LAG Descriptor Register   * -----------------------------------------   * The switch LAG descriptor register is populated by LAG descriptors. @@ -1701,20 +1843,20 @@ MLXSW_ITEM32(reg, pmlp, width, 0x00, 0, 8);   * Module number.   * Access: RW   */ -MLXSW_ITEM32_INDEXED(reg, pmlp, module, 0x04, 0, 8, 0x04, 0, false); +MLXSW_ITEM32_INDEXED(reg, pmlp, module, 0x04, 0, 8, 0x04, 0x00, false);  /* reg_pmlp_tx_lane   * Tx Lane. When rxtx field is cleared, this field is used for Rx as well.   * Access: RW   */ -MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 2, 0x04, 16, false); +MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 2, 0x04, 0x00, false);  /* reg_pmlp_rx_lane   * Rx Lane. When rxtx field is cleared, this field is ignored and Rx lane is   * equal to Tx lane.   * Access: RW   */ -MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 2, 0x04, 24, false); +MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 2, 0x04, 0x00, false);  static inline void mlxsw_reg_pmlp_pack(char *payload, u8 local_port)  { @@ -3117,10 +3259,14 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)  		return "SPVID";  	case MLXSW_REG_SPVM_ID:  		return "SPVM"; +	case MLXSW_REG_SPAFT_ID: +		return "SPAFT";  	case MLXSW_REG_SFGC_ID:  		return "SFGC";  	case MLXSW_REG_SFTR_ID:  		return "SFTR"; +	case MLXSW_REG_SFDF_ID: +		return "SFDF";  	case MLXSW_REG_SLDR_ID:  		return "SLDR";  	case MLXSW_REG_SLCR_ID: diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index ce6845d534a8..a94daa8c346c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1979,6 +1979,115 @@ static struct mlxsw_driver mlxsw_sp_driver = {  	.profile		= &mlxsw_sp_config_profile,  }; +static int +mlxsw_sp_port_fdb_flush_by_port(const struct mlxsw_sp_port *mlxsw_sp_port) +{ +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; +	char sfdf_pl[MLXSW_REG_SFDF_LEN]; + +	mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_PORT); +	mlxsw_reg_sfdf_system_port_set(sfdf_pl, mlxsw_sp_port->local_port); + +	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); +} + +static int +mlxsw_sp_port_fdb_flush_by_port_fid(const struct mlxsw_sp_port *mlxsw_sp_port, +				    u16 fid) +{ +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; +	char sfdf_pl[MLXSW_REG_SFDF_LEN]; + +	mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID); +	mlxsw_reg_sfdf_fid_set(sfdf_pl, fid); +	mlxsw_reg_sfdf_port_fid_system_port_set(sfdf_pl, +						mlxsw_sp_port->local_port); + +	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); +} + +static int +mlxsw_sp_port_fdb_flush_by_lag_id(const struct mlxsw_sp_port *mlxsw_sp_port) +{ +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; +	char sfdf_pl[MLXSW_REG_SFDF_LEN]; + +	mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_LAG); +	mlxsw_reg_sfdf_lag_id_set(sfdf_pl, mlxsw_sp_port->lag_id); + +	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); +} + +static int +mlxsw_sp_port_fdb_flush_by_lag_id_fid(const struct mlxsw_sp_port *mlxsw_sp_port, +				      u16 fid) +{ +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; +	char sfdf_pl[MLXSW_REG_SFDF_LEN]; + +	mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID); +	mlxsw_reg_sfdf_fid_set(sfdf_pl, fid); +	mlxsw_reg_sfdf_lag_fid_lag_id_set(sfdf_pl, mlxsw_sp_port->lag_id); + +	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); +} + +static int +__mlxsw_sp_port_fdb_flush(const struct mlxsw_sp_port *mlxsw_sp_port) +{ +	int err, last_err = 0; +	u16 vid; + +	for (vid = 1; vid < VLAN_N_VID - 1; vid++) { +		err = mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_port, vid); +		if (err) +			last_err = err; +	} + +	return last_err; +} + +static int +__mlxsw_sp_port_fdb_flush_lagged(const struct mlxsw_sp_port *mlxsw_sp_port) +{ +	int err, last_err = 0; +	u16 vid; + +	for (vid = 1; vid < VLAN_N_VID - 1; vid++) { +		err = mlxsw_sp_port_fdb_flush_by_lag_id_fid(mlxsw_sp_port, vid); +		if (err) +			last_err = err; +	} + +	return last_err; +} + +static int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port) +{ +	if (!list_empty(&mlxsw_sp_port->vports_list)) +		if (mlxsw_sp_port->lagged) +			return __mlxsw_sp_port_fdb_flush_lagged(mlxsw_sp_port); +		else +			return __mlxsw_sp_port_fdb_flush(mlxsw_sp_port); +	else +		if (mlxsw_sp_port->lagged) +			return mlxsw_sp_port_fdb_flush_by_lag_id(mlxsw_sp_port); +		else +			return mlxsw_sp_port_fdb_flush_by_port(mlxsw_sp_port); +} + +static int mlxsw_sp_vport_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_vport) +{ +	u16 vfid = mlxsw_sp_vport_vfid_get(mlxsw_sp_vport); +	u16 fid = mlxsw_sp_vfid_to_fid(vfid); + +	if (mlxsw_sp_vport->lagged) +		return mlxsw_sp_port_fdb_flush_by_lag_id_fid(mlxsw_sp_vport, +							     fid); +	else +		return mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_vport, fid); +} +  static bool mlxsw_sp_port_dev_check(const struct net_device *dev)  {  	return dev->netdev_ops == &mlxsw_sp_port_netdev_ops; @@ -2006,10 +2115,16 @@ static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port)  	return 0;  } -static int mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port) +static int mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, +				      bool flush_fdb)  {  	struct net_device *dev = mlxsw_sp_port->dev; +	if (flush_fdb && mlxsw_sp_port_fdb_flush(mlxsw_sp_port)) +		netdev_err(mlxsw_sp_port->dev, "Failed to flush FDB\n"); + +	mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); +  	mlxsw_sp_port->learning = 0;  	mlxsw_sp_port->learning_sync = 0;  	mlxsw_sp_port->uc_flood = 0; @@ -2200,10 +2315,15 @@ err_col_port_enable:  	return err;  } +static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport, +				       struct net_device *br_dev, +				       bool flush_fdb); +  static int mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,  				   struct net_device *lag_dev)  {  	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; +	struct mlxsw_sp_port *mlxsw_sp_vport;  	struct mlxsw_sp_upper *lag;  	u16 lag_id = mlxsw_sp_port->lag_id;  	int err; @@ -2220,7 +2340,30 @@ static int mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,  	if (err)  		return err; +	/* In case we leave a LAG device that has bridges built on top, +	 * then their teardown sequence is never issued and we need to +	 * invoke the necessary cleanup routines ourselves. +	 */ +	list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, +			    vport.list) { +		struct net_device *br_dev; + +		if (!mlxsw_sp_vport->bridged) +			continue; + +		br_dev = mlxsw_sp_vport_br_get(mlxsw_sp_vport); +		mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport, br_dev, false); +	} + +	if (mlxsw_sp_port->bridged) { +		mlxsw_sp_port_active_vlans_del(mlxsw_sp_port); +		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, false); +		mlxsw_sp_master_bridge_dec(mlxsw_sp, NULL); +	} +  	if (lag->ref_count == 1) { +		if (mlxsw_sp_port_fdb_flush_by_lag_id(mlxsw_sp_port)) +			netdev_err(mlxsw_sp_port->dev, "Failed to flush FDB\n");  		err = mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);  		if (err)  			return err; @@ -2272,9 +2415,6 @@ static int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port,  	return mlxsw_sp_port_lag_tx_en_set(mlxsw_sp_port, info->tx_enabled);  } -static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport, -				       struct net_device *br_dev); -  static int mlxsw_sp_port_vlan_link(struct mlxsw_sp_port *mlxsw_sp_port,  				   struct net_device *vlan_dev)  { @@ -2312,7 +2452,7 @@ static int mlxsw_sp_port_vlan_unlink(struct mlxsw_sp_port *mlxsw_sp_port,  		struct net_device *br_dev;  		br_dev = mlxsw_sp_vport_br_get(mlxsw_sp_vport); -		mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport, br_dev); +		mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport, br_dev, true);  	}  	mlxsw_sp_vport->dev = mlxsw_sp_port->dev; @@ -2374,7 +2514,8 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev,  				}  				mlxsw_sp_master_bridge_inc(mlxsw_sp, upper_dev);  			} else { -				err = mlxsw_sp_port_bridge_leave(mlxsw_sp_port); +				err = mlxsw_sp_port_bridge_leave(mlxsw_sp_port, +								 true);  				mlxsw_sp_master_bridge_dec(mlxsw_sp, upper_dev);  				if (err) {  					netdev_err(dev, "Failed to leave bridge\n"); @@ -2541,7 +2682,8 @@ static void mlxsw_sp_br_vfid_destroy(struct mlxsw_sp *mlxsw_sp,  }  static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport, -				       struct net_device *br_dev) +				       struct net_device *br_dev, +				       bool flush_fdb)  {  	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;  	u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); @@ -2604,6 +2746,16 @@ static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport,  		goto err_vport_flood_set;  	} +	err = mlxsw_sp_port_stp_state_set(mlxsw_sp_vport, vid, +					  MLXSW_REG_SPMS_STATE_FORWARDING); +	if (err) { +		netdev_err(dev, "Failed to set STP state\n"); +		goto err_port_stp_state_set; +	} + +	if (flush_fdb && mlxsw_sp_vport_fdb_flush(mlxsw_sp_vport)) +		netdev_err(dev, "Failed to flush FDB\n"); +  	/* Switch between the vFIDs and destroy the old one if needed. */  	new_vfid->nr_vports++;  	mlxsw_sp_vport->vport.vfid = new_vfid; @@ -2618,6 +2770,7 @@ static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport,  	return 0; +err_port_stp_state_set:  err_vport_flood_set:  err_port_vid_learning_set:  err_port_vid_to_fid_validate: @@ -2777,7 +2930,7 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev,  			if (!mlxsw_sp_vport)  				return NOTIFY_DONE;  			err = mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport, -							  upper_dev); +							  upper_dev, true);  			if (err) {  				netdev_err(dev, "Failed to leave bridge\n");  				return NOTIFY_BAD; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index a23dc610d259..3b89ed2f3c76 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -120,7 +120,6 @@ struct mlxsw_sp {  	} fdb_notify;  #define MLXSW_SP_DEFAULT_AGEING_TIME 300  	u32 ageing_time; -	struct mutex fdb_lock;	/* Make sure FDB sessions are atomic. */  	struct mlxsw_sp_upper master_bridge;  	struct mlxsw_sp_upper lags[MLXSW_SP_LAG_MAX];  }; @@ -254,5 +253,7 @@ int mlxsw_sp_port_kill_vid(struct net_device *dev,  			   __be16 __always_unused proto, u16 vid);  int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,  			     bool set, bool only_uc); +void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);  #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 45479ef5bcf4..7b56098acc58 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -45,6 +45,7 @@  #include <linux/if_bridge.h>  #include <linux/workqueue.h>  #include <linux/jiffies.h> +#include <linux/rtnetlink.h>  #include <net/switchdev.h>  #include "spectrum.h" @@ -124,14 +125,14 @@ static int mlxsw_sp_port_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,  	int err;  	switch (state) { -	case BR_STATE_DISABLED: /* fall-through */  	case BR_STATE_FORWARDING:  		spms_state = MLXSW_REG_SPMS_STATE_FORWARDING;  		break; -	case BR_STATE_LISTENING: /* fall-through */  	case BR_STATE_LEARNING:  		spms_state = MLXSW_REG_SPMS_STATE_LEARNING;  		break; +	case BR_STATE_LISTENING: /* fall-through */ +	case BR_STATE_DISABLED: /* fall-through */  	case BR_STATE_BLOCKING:  		spms_state = MLXSW_REG_SPMS_STATE_DISCARDING;  		break; @@ -369,7 +370,8 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,  	return err;  } -static int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, +				    u16 vid)  {  	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;  	char spvid_pl[MLXSW_REG_SPVID_LEN]; @@ -378,6 +380,53 @@ static int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)  	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl);  } +static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port, +					    bool allow) +{ +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; +	char spaft_pl[MLXSW_REG_SPAFT_LEN]; + +	mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow); +	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl); +} + +int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ +	struct net_device *dev = mlxsw_sp_port->dev; +	int err; + +	if (!vid) { +		err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false); +		if (err) { +			netdev_err(dev, "Failed to disallow untagged traffic\n"); +			return err; +		} +	} else { +		err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid); +		if (err) { +			netdev_err(dev, "Failed to set PVID\n"); +			return err; +		} + +		/* Only allow if not already allowed. */ +		if (!mlxsw_sp_port->pvid) { +			err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, +							       true); +			if (err) { +				netdev_err(dev, "Failed to allow untagged traffic\n"); +				goto err_port_allow_untagged_set; +			} +		} +	} + +	mlxsw_sp_port->pvid = vid; +	return 0; + +err_port_allow_untagged_set: +	__mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid); +	return err; +} +  static int mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid)  {  	char sfmr_pl[MLXSW_REG_SFMR_LEN]; @@ -539,7 +588,12 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,  			netdev_err(dev, "Unable to add PVID %d\n", vid_begin);  			goto err_port_pvid_set;  		} -		mlxsw_sp_port->pvid = vid_begin; +	} else if (!flag_pvid && old_pvid >= vid_begin && old_pvid <= vid_end) { +		err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0); +		if (err) { +			netdev_err(dev, "Unable to del PVID\n"); +			goto err_port_pvid_set; +		}  	}  	/* Changing activity bits only if HW operation succeded */ @@ -891,20 +945,18 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,  		return err;  	} +	if (init) +		goto out; +  	pvid = mlxsw_sp_port->pvid; -	if (pvid >= vid_begin && pvid <= vid_end && pvid != 1) { -		/* Default VLAN is always 1 */ -		err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); +	if (pvid >= vid_begin && pvid <= vid_end) { +		err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0);  		if (err) {  			netdev_err(dev, "Unable to del PVID %d\n", pvid);  			return err;  		} -		mlxsw_sp_port->pvid = 1;  	} -	if (init) -		goto out; -  	err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid_begin, vid_end,  					false, false);  	if (err) { @@ -936,6 +988,14 @@ static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,  					 vlan->vid_begin, vlan->vid_end, false);  } +void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port) +{ +	u16 vid; + +	for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) +		__mlxsw_sp_port_vlans_del(mlxsw_sp_port, vid, vid, false); +} +  static int  mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port,  			     const struct switchdev_obj_port_fdb *fdb) @@ -1040,10 +1100,12 @@ static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp,  static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,  				  struct switchdev_obj_port_fdb *fdb, -				  switchdev_obj_dump_cb_t *cb) +				  switchdev_obj_dump_cb_t *cb, +				  struct net_device *orig_dev)  {  	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; -	u16 vport_vid = 0, vport_fid = 0; +	struct mlxsw_sp_port *tmp; +	u16 vport_fid = 0;  	char *sfd_pl;  	char mac[ETH_ALEN];  	u16 fid; @@ -1058,13 +1120,11 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,  	if (!sfd_pl)  		return -ENOMEM; -	mutex_lock(&mlxsw_sp_port->mlxsw_sp->fdb_lock);  	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {  		u16 tmp;  		tmp = mlxsw_sp_vport_vfid_get(mlxsw_sp_port);  		vport_fid = mlxsw_sp_vfid_to_fid(tmp); -		vport_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port);  	}  	mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0); @@ -1088,12 +1148,13 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,  				mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, &fid,  							&local_port);  				if (local_port == mlxsw_sp_port->local_port) { -					if (vport_fid && vport_fid != fid) -						continue; -					else if (vport_fid) -						fdb->vid = vport_vid; -					else +					if (vport_fid && vport_fid == fid) +						fdb->vid = 0; +					else if (!vport_fid && +						 !mlxsw_sp_fid_is_vfid(fid))  						fdb->vid = fid; +					else +						continue;  					ether_addr_copy(fdb->addr, mac);  					fdb->ndm_state = NUD_REACHABLE;  					err = cb(&fdb->obj); @@ -1104,14 +1165,22 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,  			case MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG:  				mlxsw_reg_sfd_uc_lag_unpack(sfd_pl, i,  							    mac, &fid, &lag_id); -				if (mlxsw_sp_port == -				    mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id)) { -					if (vport_fid && vport_fid != fid) +				tmp = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id); +				if (tmp && tmp->local_port == +				    mlxsw_sp_port->local_port) { +					/* LAG records can only point to LAG +					 * devices or VLAN devices on top. +					 */ +					if (!netif_is_lag_master(orig_dev) && +					    !is_vlan_dev(orig_dev))  						continue; -					else if (vport_fid) -						fdb->vid = vport_vid; -					else +					if (vport_fid && vport_fid == fid) +						fdb->vid = 0; +					else if (!vport_fid && +						 !mlxsw_sp_fid_is_vfid(fid))  						fdb->vid = fid; +					else +						continue;  					ether_addr_copy(fdb->addr, mac);  					fdb->ndm_state = NUD_REACHABLE;  					err = cb(&fdb->obj); @@ -1124,7 +1193,6 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,  	} while (num_rec == MLXSW_REG_SFD_REC_MAX_COUNT);  out: -	mutex_unlock(&mlxsw_sp_port->mlxsw_sp->fdb_lock);  	kfree(sfd_pl);  	return stored_err ? stored_err : err;  } @@ -1176,7 +1244,8 @@ static int mlxsw_sp_port_obj_dump(struct net_device *dev,  		break;  	case SWITCHDEV_OBJ_ID_PORT_FDB:  		err = mlxsw_sp_port_fdb_dump(mlxsw_sp_port, -					     SWITCHDEV_OBJ_PORT_FDB(obj), cb); +					     SWITCHDEV_OBJ_PORT_FDB(obj), cb, +					     obj->orig_dev);  		break;  	default:  		err = -EOPNOTSUPP; @@ -1194,14 +1263,14 @@ static const struct switchdev_ops mlxsw_sp_port_switchdev_ops = {  	.switchdev_port_obj_dump	= mlxsw_sp_port_obj_dump,  }; -static void mlxsw_sp_fdb_call_notifiers(bool learning, bool learning_sync, -					bool adding, char *mac, u16 vid, +static void mlxsw_sp_fdb_call_notifiers(bool learning_sync, bool adding, +					char *mac, u16 vid,  					struct net_device *dev)  {  	struct switchdev_notifier_fdb_info info;  	unsigned long notifier_type; -	if (learning && learning_sync) { +	if (learning_sync) {  		info.addr = mac;  		info.vid = vid;  		notifier_type = adding ? SWITCHDEV_FDB_ADD : SWITCHDEV_FDB_DEL; @@ -1237,7 +1306,7 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,  			netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n");  			goto just_remove;  		} -		vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); +		vid = 0;  		/* Override the physical port with the vPort. */  		mlxsw_sp_port = mlxsw_sp_vport;  	} else { @@ -1257,8 +1326,7 @@ do_fdb_op:  	if (!do_notification)  		return; -	mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning, -				    mlxsw_sp_port->learning_sync, +	mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning_sync,  				    adding, mac, vid, mlxsw_sp_port->dev);  	return; @@ -1273,6 +1341,7 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,  						bool adding)  {  	struct mlxsw_sp_port *mlxsw_sp_port; +	struct net_device *dev;  	char mac[ETH_ALEN];  	u16 lag_vid = 0;  	u16 lag_id; @@ -1298,11 +1367,13 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,  			goto just_remove;  		} -		vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); -		lag_vid = vid; +		lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); +		dev = mlxsw_sp_vport->dev; +		vid = 0;  		/* Override the physical port with the vPort. */  		mlxsw_sp_port = mlxsw_sp_vport;  	} else { +		dev = mlxsw_sp_lag_get(mlxsw_sp, lag_id)->dev;  		vid = fid;  	} @@ -1319,10 +1390,8 @@ do_fdb_op:  	if (!do_notification)  		return; -	mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning, -				    mlxsw_sp_port->learning_sync, -				    adding, mac, vid, -				    mlxsw_sp_lag_get(mlxsw_sp, lag_id)->dev); +	mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning_sync, adding, mac, +				    vid, dev);  	return;  just_remove: @@ -1374,7 +1443,7 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)  	mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work); -	mutex_lock(&mlxsw_sp->fdb_lock); +	rtnl_lock();  	do {  		mlxsw_reg_sfn_pack(sfn_pl);  		err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl); @@ -1387,7 +1456,7 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)  			mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);  	} while (num_rec); -	mutex_unlock(&mlxsw_sp->fdb_lock); +	rtnl_unlock();  	kfree(sfn_pl);  	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); @@ -1402,7 +1471,6 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)  		dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n");  		return err;  	} -	mutex_init(&mlxsw_sp->fdb_lock);  	INIT_DELAYED_WORK(&mlxsw_sp->fdb_notify.dw, mlxsw_sp_fdb_notify_work);  	mlxsw_sp->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;  	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c index a10c928bbd6b..3e67f451f2ab 100644 --- a/drivers/net/ethernet/moxa/moxart_ether.c +++ b/drivers/net/ethernet/moxa/moxart_ether.c @@ -28,6 +28,16 @@  #include "moxart_ether.h" +static inline void moxart_desc_write(u32 data, u32 *desc) +{ +	*desc = cpu_to_le32(data); +} + +static inline u32 moxart_desc_read(u32 *desc) +{ +	return le32_to_cpu(*desc); +} +  static inline void moxart_emac_write(struct net_device *ndev,  				     unsigned int reg, unsigned long value)  { @@ -112,7 +122,7 @@ static void moxart_mac_enable(struct net_device *ndev)  static void moxart_mac_setup_desc_ring(struct net_device *ndev)  {  	struct moxart_mac_priv_t *priv = netdev_priv(ndev); -	void __iomem *desc; +	void *desc;  	int i;  	for (i = 0; i < TX_DESC_NUM; i++) { @@ -121,7 +131,7 @@ static void moxart_mac_setup_desc_ring(struct net_device *ndev)  		priv->tx_buf[i] = priv->tx_buf_base + priv->tx_buf_size * i;  	} -	writel(TX_DESC1_END, desc + TX_REG_OFFSET_DESC1); +	moxart_desc_write(TX_DESC1_END, desc + TX_REG_OFFSET_DESC1);  	priv->tx_head = 0;  	priv->tx_tail = 0; @@ -129,8 +139,8 @@ static void moxart_mac_setup_desc_ring(struct net_device *ndev)  	for (i = 0; i < RX_DESC_NUM; i++) {  		desc = priv->rx_desc_base + i * RX_REG_DESC_SIZE;  		memset(desc, 0, RX_REG_DESC_SIZE); -		writel(RX_DESC0_DMA_OWN, desc + RX_REG_OFFSET_DESC0); -		writel(RX_BUF_SIZE & RX_DESC1_BUF_SIZE_MASK, +		moxart_desc_write(RX_DESC0_DMA_OWN, desc + RX_REG_OFFSET_DESC0); +		moxart_desc_write(RX_BUF_SIZE & RX_DESC1_BUF_SIZE_MASK,  		       desc + RX_REG_OFFSET_DESC1);  		priv->rx_buf[i] = priv->rx_buf_base + priv->rx_buf_size * i; @@ -141,12 +151,12 @@ static void moxart_mac_setup_desc_ring(struct net_device *ndev)  		if (dma_mapping_error(&ndev->dev, priv->rx_mapping[i]))  			netdev_err(ndev, "DMA mapping error\n"); -		writel(priv->rx_mapping[i], +		moxart_desc_write(priv->rx_mapping[i],  		       desc + RX_REG_OFFSET_DESC2 + RX_DESC2_ADDRESS_PHYS); -		writel(priv->rx_buf[i], +		moxart_desc_write((uintptr_t)priv->rx_buf[i],  		       desc + RX_REG_OFFSET_DESC2 + RX_DESC2_ADDRESS_VIRT);  	} -	writel(RX_DESC1_END, desc + RX_REG_OFFSET_DESC1); +	moxart_desc_write(RX_DESC1_END, desc + RX_REG_OFFSET_DESC1);  	priv->rx_head = 0; @@ -201,14 +211,15 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)  						      napi);  	struct net_device *ndev = priv->ndev;  	struct sk_buff *skb; -	void __iomem *desc; +	void *desc;  	unsigned int desc0, len;  	int rx_head = priv->rx_head;  	int rx = 0;  	while (rx < budget) {  		desc = priv->rx_desc_base + (RX_REG_DESC_SIZE * rx_head); -		desc0 = readl(desc + RX_REG_OFFSET_DESC0); +		desc0 = moxart_desc_read(desc + RX_REG_OFFSET_DESC0); +		rmb(); /* ensure desc0 is up to date */  		if (desc0 & RX_DESC0_DMA_OWN)  			break; @@ -250,7 +261,8 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)  			priv->stats.multicast++;  rx_next: -		writel(RX_DESC0_DMA_OWN, desc + RX_REG_OFFSET_DESC0); +		wmb(); /* prevent setting ownership back too early */ +		moxart_desc_write(RX_DESC0_DMA_OWN, desc + RX_REG_OFFSET_DESC0);  		rx_head = RX_NEXT(rx_head);  		priv->rx_head = rx_head; @@ -310,7 +322,7 @@ static irqreturn_t moxart_mac_interrupt(int irq, void *dev_id)  static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)  {  	struct moxart_mac_priv_t *priv = netdev_priv(ndev); -	void __iomem *desc; +	void *desc;  	unsigned int len;  	unsigned int tx_head = priv->tx_head;  	u32 txdes1; @@ -319,11 +331,12 @@ static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	desc = priv->tx_desc_base + (TX_REG_DESC_SIZE * tx_head);  	spin_lock_irq(&priv->txlock); -	if (readl(desc + TX_REG_OFFSET_DESC0) & TX_DESC0_DMA_OWN) { +	if (moxart_desc_read(desc + TX_REG_OFFSET_DESC0) & TX_DESC0_DMA_OWN) {  		net_dbg_ratelimited("no TX space for packet\n");  		priv->stats.tx_dropped++;  		goto out_unlock;  	} +	rmb(); /* ensure data is only read that had TX_DESC0_DMA_OWN cleared */  	len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len; @@ -337,9 +350,9 @@ static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	priv->tx_len[tx_head] = len;  	priv->tx_skb[tx_head] = skb; -	writel(priv->tx_mapping[tx_head], +	moxart_desc_write(priv->tx_mapping[tx_head],  	       desc + TX_REG_OFFSET_DESC2 + TX_DESC2_ADDRESS_PHYS); -	writel(skb->data, +	moxart_desc_write((uintptr_t)skb->data,  	       desc + TX_REG_OFFSET_DESC2 + TX_DESC2_ADDRESS_VIRT);  	if (skb->len < ETH_ZLEN) { @@ -354,8 +367,9 @@ static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	txdes1 = TX_DESC1_LTS | TX_DESC1_FTS | (len & TX_DESC1_BUF_SIZE_MASK);  	if (tx_head == TX_DESC_NUM_MASK)  		txdes1 |= TX_DESC1_END; -	writel(txdes1, desc + TX_REG_OFFSET_DESC1); -	writel(TX_DESC0_DMA_OWN, desc + TX_REG_OFFSET_DESC0); +	moxart_desc_write(txdes1, desc + TX_REG_OFFSET_DESC1); +	wmb(); /* flush descriptor before transferring ownership */ +	moxart_desc_write(TX_DESC0_DMA_OWN, desc + TX_REG_OFFSET_DESC0);  	/* start to send packet */  	writel(0xffffffff, priv->base + REG_TX_POLL_DEMAND); @@ -460,9 +474,9 @@ static int moxart_mac_probe(struct platform_device *pdev)  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	ndev->base_addr = res->start;  	priv->base = devm_ioremap_resource(p_dev, res); -	ret = IS_ERR(priv->base); -	if (ret) { +	if (IS_ERR(priv->base)) {  		dev_err(p_dev, "devm_ioremap_resource failed\n"); +		ret = PTR_ERR(priv->base);  		goto init_fail;  	} diff --git a/drivers/net/ethernet/moxa/moxart_ether.h b/drivers/net/ethernet/moxa/moxart_ether.h index 2be9280d608c..93a9563ac7c6 100644 --- a/drivers/net/ethernet/moxa/moxart_ether.h +++ b/drivers/net/ethernet/moxa/moxart_ether.h @@ -300,7 +300,7 @@ struct moxart_mac_priv_t {  	dma_addr_t rx_base;  	dma_addr_t rx_mapping[RX_DESC_NUM]; -	void __iomem *rx_desc_base; +	void *rx_desc_base;  	unsigned char *rx_buf_base;  	unsigned char *rx_buf[RX_DESC_NUM];  	unsigned int rx_head; @@ -308,7 +308,7 @@ struct moxart_mac_priv_t {  	dma_addr_t tx_base;  	dma_addr_t tx_mapping[TX_DESC_NUM]; -	void __iomem *tx_desc_base; +	void *tx_desc_base;  	unsigned char *tx_buf_base;  	unsigned char *tx_buf[RX_DESC_NUM];  	unsigned int tx_head; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index 50d5604833ed..e0993eba5df3 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -2223,8 +2223,6 @@ static irqreturn_t vxge_isr_napi(int irq, void *dev_id)  	return IRQ_NONE;  } -#ifdef CONFIG_PCI_MSI -  static irqreturn_t vxge_tx_msix_handle(int irq, void *dev_id)  {  	struct vxge_fifo *fifo = (struct vxge_fifo *)dev_id; @@ -2442,16 +2440,13 @@ static void vxge_rem_msix_isr(struct vxgedev *vdev)  	if (vdev->config.intr_type == MSI_X)  		pci_disable_msix(vdev->pdev);  } -#endif  static void vxge_rem_isr(struct vxgedev *vdev)  { -#ifdef CONFIG_PCI_MSI -	if (vdev->config.intr_type == MSI_X) { +	if (IS_ENABLED(CONFIG_PCI_MSI) && +	    vdev->config.intr_type == MSI_X) {  		vxge_rem_msix_isr(vdev); -	} else -#endif -	if (vdev->config.intr_type == INTA) { +	} else if (vdev->config.intr_type == INTA) {  			synchronize_irq(vdev->pdev->irq);  			free_irq(vdev->pdev->irq, vdev);  	} @@ -2460,11 +2455,10 @@ static void vxge_rem_isr(struct vxgedev *vdev)  static int vxge_add_isr(struct vxgedev *vdev)  {  	int ret = 0; -#ifdef CONFIG_PCI_MSI  	int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0;  	int pci_fun = PCI_FUNC(vdev->pdev->devfn); -	if (vdev->config.intr_type == MSI_X) +	if (IS_ENABLED(CONFIG_PCI_MSI) && vdev->config.intr_type == MSI_X)  		ret = vxge_enable_msix(vdev);  	if (ret) { @@ -2475,7 +2469,7 @@ static int vxge_add_isr(struct vxgedev *vdev)  		vdev->config.intr_type = INTA;  	} -	if (vdev->config.intr_type == MSI_X) { +	if (IS_ENABLED(CONFIG_PCI_MSI) && vdev->config.intr_type == MSI_X) {  		for (intr_idx = 0;  		     intr_idx < (vdev->no_of_vpath *  			VXGE_HW_VPATH_MSIX_ACTIVE); intr_idx++) { @@ -2576,9 +2570,8 @@ static int vxge_add_isr(struct vxgedev *vdev)  		vdev->vxge_entries[intr_cnt].in_use = 1;  		vdev->vxge_entries[intr_cnt].arg = &vdev->vpaths[0];  	} -INTA_MODE: -#endif +INTA_MODE:  	if (vdev->config.intr_type == INTA) {  		snprintf(vdev->desc[0], VXGE_INTR_STRLEN,  			"%s:vxge:INTA", vdev->ndev->name); @@ -3889,12 +3882,12 @@ static void vxge_device_config_init(struct vxge_hw_device_config *device_config,  	if (max_mac_vpath > VXGE_MAX_MAC_ADDR_COUNT)  		max_mac_vpath = VXGE_MAX_MAC_ADDR_COUNT; -#ifndef CONFIG_PCI_MSI -	vxge_debug_init(VXGE_ERR, -		"%s: This Kernel does not support " -		"MSI-X. Defaulting to INTA", VXGE_DRIVER_NAME); -	*intr_type = INTA; -#endif +	if (!IS_ENABLED(CONFIG_PCI_MSI)) { +		vxge_debug_init(VXGE_ERR, +			"%s: This Kernel does not support " +			"MSI-X. Defaulting to INTA", VXGE_DRIVER_NAME); +		*intr_type = INTA; +	}  	/* Configure whether MSI-X or IRQL. */  	switch (*intr_type) { diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c index afa445842f3e..52d9a94aebb9 100644 --- a/drivers/net/ethernet/nuvoton/w90p910_ether.c +++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c @@ -1038,7 +1038,7 @@ static int w90p910_ether_probe(struct platform_device *pdev)  	error = register_netdev(dev);  	if (error != 0) { -		dev_err(&pdev->dev, "Regiter EMC w90p910 FAILED\n"); +		dev_err(&pdev->dev, "Register EMC w90p910 FAILED\n");  		error = -ENODEV;  		goto failed_put_rmiiclk;  	} diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 689a4a5c8dcf..1ef03939d25f 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -811,7 +811,7 @@ qcaspi_netdev_setup(struct net_device *dev)  	dev->netdev_ops = &qcaspi_netdev_ops;  	qcaspi_set_ethtool_ops(dev);  	dev->watchdog_timeo = QCASPI_TX_TIMEOUT; -	dev->flags = IFF_MULTICAST; +	dev->priv_flags &= ~IFF_TX_SKB_SHARING;  	dev->tx_queue_len = 100;  	qca = netdev_priv(dev); diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 17d5571d0432..dd2cf3738b73 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -4933,8 +4933,6 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)  		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);  		break;  	case RTL_GIGA_MAC_VER_40: -		RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF); -		break;  	case RTL_GIGA_MAC_VER_41:  	case RTL_GIGA_MAC_VER_42:  	case RTL_GIGA_MAC_VER_43: @@ -4943,8 +4941,6 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)  	case RTL_GIGA_MAC_VER_46:  	case RTL_GIGA_MAC_VER_47:  	case RTL_GIGA_MAC_VER_48: -		RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF); -		break;  	case RTL_GIGA_MAC_VER_49:  	case RTL_GIGA_MAC_VER_50:  	case RTL_GIGA_MAC_VER_51: @@ -6137,28 +6133,28 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)  		sw_cnt_1ms_ini = 16000000/rg_saw_cnt;  		sw_cnt_1ms_ini &= 0x0fff;  		data = r8168_mac_ocp_read(tp, 0xd412); -		data &= 0x0fff; +		data &= ~0x0fff;  		data |= sw_cnt_1ms_ini;  		r8168_mac_ocp_write(tp, 0xd412, data);  	}  	data = r8168_mac_ocp_read(tp, 0xe056); -	data &= 0xf0; -	data |= 0x07; +	data &= ~0xf0; +	data |= 0x70;  	r8168_mac_ocp_write(tp, 0xe056, data);  	data = r8168_mac_ocp_read(tp, 0xe052); -	data &= 0x8008; -	data |= 0x6000; +	data &= ~0x6000; +	data |= 0x8008;  	r8168_mac_ocp_write(tp, 0xe052, data);  	data = r8168_mac_ocp_read(tp, 0xe0d6); -	data &= 0x01ff; +	data &= ~0x01ff;  	data |= 0x017f;  	r8168_mac_ocp_write(tp, 0xe0d6, data);  	data = r8168_mac_ocp_read(tp, 0xd420); -	data &= 0x0fff; +	data &= ~0x0fff;  	data |= 0x047f;  	r8168_mac_ocp_write(tp, 0xd420, data); @@ -7730,10 +7726,13 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)  {  	struct rtl8169_private *tp = netdev_priv(dev);  	void __iomem *ioaddr = tp->mmio_addr; +	struct pci_dev *pdev = tp->pci_dev;  	struct rtl8169_counters *counters = tp->counters;  	unsigned int start; -	if (netif_running(dev)) +	pm_runtime_get_noresume(&pdev->dev); + +	if (netif_running(dev) && pm_runtime_active(&pdev->dev))  		rtl8169_rx_missed(dev, ioaddr);  	do { @@ -7761,7 +7760,8 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)  	 * Fetch additonal counter values missing in stats collected by driver  	 * from tally counters.  	 */ -	rtl8169_update_counters(dev); +	if (pm_runtime_active(&pdev->dev)) +		rtl8169_update_counters(dev);  	/*  	 * Subtract values fetched during initalization. @@ -7774,6 +7774,8 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)  	stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted) -  		le16_to_cpu(tp->tc_offset.tx_aborted); +	pm_runtime_put_noidle(&pdev->dev); +  	return stats;  } @@ -7853,6 +7855,10 @@ static int rtl8169_runtime_suspend(struct device *device)  	rtl8169_net_suspend(dev); +	/* Update counters before going runtime suspend */ +	rtl8169_rx_missed(dev, tp->mmio_addr); +	rtl8169_update_counters(dev); +  	return 0;  } diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index ac43ed914fcf..86449c357168 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1139,7 +1139,8 @@ static int ravb_set_ringparam(struct net_device *ndev,  	if (netif_running(ndev)) {  		netif_device_detach(ndev);  		/* Stop PTP Clock driver */ -		ravb_ptp_stop(ndev); +		if (priv->chip_id == RCAR_GEN2) +			ravb_ptp_stop(ndev);  		/* Wait for DMA stopping */  		error = ravb_stop_dma(ndev);  		if (error) { @@ -1170,7 +1171,8 @@ static int ravb_set_ringparam(struct net_device *ndev,  		ravb_emac_init(ndev);  		/* Initialise PTP Clock driver */ -		ravb_ptp_init(ndev, priv->pdev); +		if (priv->chip_id == RCAR_GEN2) +			ravb_ptp_init(ndev, priv->pdev);  		netif_device_attach(ndev);  	} @@ -1298,7 +1300,8 @@ static void ravb_tx_timeout_work(struct work_struct *work)  	netif_tx_stop_all_queues(ndev);  	/* Stop PTP Clock driver */ -	ravb_ptp_stop(ndev); +	if (priv->chip_id == RCAR_GEN2) +		ravb_ptp_stop(ndev);  	/* Wait for DMA stopping */  	ravb_stop_dma(ndev); @@ -1311,7 +1314,8 @@ static void ravb_tx_timeout_work(struct work_struct *work)  	ravb_emac_init(ndev);  	/* Initialise PTP Clock driver */ -	ravb_ptp_init(ndev, priv->pdev); +	if (priv->chip_id == RCAR_GEN2) +		ravb_ptp_init(ndev, priv->pdev);  	netif_tx_start_all_queues(ndev);  } @@ -1718,7 +1722,6 @@ static int ravb_set_gti(struct net_device *ndev)  static int ravb_probe(struct platform_device *pdev)  {  	struct device_node *np = pdev->dev.of_node; -	const struct of_device_id *match;  	struct ravb_private *priv;  	enum ravb_chip_id chip_id;  	struct net_device *ndev; @@ -1750,8 +1753,7 @@ static int ravb_probe(struct platform_device *pdev)  	ndev->base_addr = res->start;  	ndev->dma = -1; -	match = of_match_device(of_match_ptr(ravb_match_table), &pdev->dev); -	chip_id = (enum ravb_chip_id)match->data; +	chip_id = (enum ravb_chip_id)of_device_get_match_data(&pdev->dev);  	if (chip_id == RCAR_GEN3)  		irq = platform_get_irq_byname(pdev, "ch22"); @@ -1814,10 +1816,6 @@ static int ravb_probe(struct platform_device *pdev)  			   CCC_OPC_CONFIG | CCC_GAC | CCC_CSEL_HPB, CCC);  	} -	/* Set CSEL value */ -	ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) | CCC_CSEL_HPB, -		   CCC); -  	/* Set GTI value */  	error = ravb_set_gti(ndev);  	if (error) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index dfa9e59c9442..738449992876 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3061,15 +3061,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)  	mdp->ether_link_active_low = pd->ether_link_active_low;  	/* set cpu data */ -	if (id) { +	if (id)  		mdp->cd = (struct sh_eth_cpu_data *)id->driver_data; -	} else	{ -		const struct of_device_id *match; +	else +		mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev); -		match = of_match_device(of_match_ptr(sh_eth_match_table), -					&pdev->dev); -		mdp->cd = (struct sh_eth_cpu_data *)match->data; -	}  	mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type);  	if (!mdp->reg_offset) {  		dev_err(&pdev->dev, "Unknown register type (%d)\n", diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index a4ab71d43e4e..166a7fc87e2f 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3531,12 +3531,14 @@ static void rocker_port_fdb_learn_work(struct work_struct *work)  	info.addr = lw->addr;  	info.vid = lw->vid; +	rtnl_lock();  	if (learned && removing)  		call_switchdev_notifiers(SWITCHDEV_FDB_DEL,  					 lw->rocker_port->dev, &info.info);  	else if (learned && !removing)  		call_switchdev_notifiers(SWITCHDEV_FDB_ADD,  					 lw->rocker_port->dev, &info.info); +	rtnl_unlock();  	rocker_port_kfree(lw->trans, work);  } diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 0e2fc1a844ab..db7db8ac4ca3 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2342,8 +2342,8 @@ static int smc_drv_probe(struct platform_device *pdev)  	}  	ndev->irq = platform_get_irq(pdev, 0); -	if (ndev->irq <= 0) { -		ret = -ENODEV; +	if (ndev->irq < 0) { +		ret = ndev->irq;  		goto out_release_io;  	}  	/* diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 0faf16336035..efb54f356a67 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -199,21 +199,12 @@ int stmmac_mdio_register(struct net_device *ndev)  	struct stmmac_priv *priv = netdev_priv(ndev);  	struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;  	int addr, found; -	struct device_node *mdio_node = NULL; -	struct device_node *child_node = NULL; +	struct device_node *mdio_node = priv->plat->mdio_node;  	if (!mdio_bus_data)  		return 0;  	if (IS_ENABLED(CONFIG_OF)) { -		for_each_child_of_node(priv->device->of_node, child_node) { -			if (of_device_is_compatible(child_node, -						    "snps,dwmac-mdio")) { -				mdio_node = child_node; -				break; -			} -		} -  		if (mdio_node) {  			netdev_dbg(ndev, "FOUND MDIO subnode\n");  		} else { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 6a52fa18cbf2..4514ba73d961 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -110,6 +110,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)  	struct device_node *np = pdev->dev.of_node;  	struct plat_stmmacenet_data *plat;  	struct stmmac_dma_cfg *dma_cfg; +	struct device_node *child_node = NULL;  	plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);  	if (!plat) @@ -140,13 +141,19 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)  		plat->phy_node = of_node_get(np);  	} +	for_each_child_of_node(np, child_node) +		if (of_device_is_compatible(child_node,	"snps,dwmac-mdio")) { +			plat->mdio_node = child_node; +			break; +		} +  	/* "snps,phy-addr" is not a standard property. Mark it as deprecated  	 * and warn of its use. Remove this when phy node support is added.  	 */  	if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)  		dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n"); -	if ((plat->phy_node && !of_phy_is_fixed_link(np)) || plat->phy_bus_name) +	if ((plat->phy_node && !of_phy_is_fixed_link(np)) || !plat->mdio_node)  		plat->mdio_bus_data = NULL;  	else  		plat->mdio_bus_data = diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index ab6051a43134..9cc45649f477 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -3341,7 +3341,7 @@ static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp,  	niu_hash_page(rp, page, addr);  	if (rp->rbr_blocks_per_page > 1) -		atomic_add(rp->rbr_blocks_per_page - 1, &page->_count); +		page_ref_add(page, rp->rbr_blocks_per_page - 1);  	for (i = 0; i < rp->rbr_blocks_per_page; i++) {  		__le32 *rbr = &rp->rbr[start_index + i]; diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index e23a642357e7..2437227712dc 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -51,7 +51,6 @@  #endif  #ifdef CONFIG_PPC_PMAC -#include <asm/pci-bridge.h>  #include <asm/prom.h>  #include <asm/machdep.h>  #include <asm/pmac_feature.h> diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index cc106d892e29..23fa29877f5b 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -389,17 +389,27 @@ static int vnet_rx_one(struct vnet_port *port, struct vio_net_desc *desc)  	if (vio_version_after_eq(&port->vio, 1, 8)) {  		struct vio_net_dext *dext = vio_net_ext(desc); +		skb_reset_network_header(skb); +  		if (dext->flags & VNET_PKT_HCK_IPV4_HDRCKSUM) {  			if (skb->protocol == ETH_P_IP) { -				struct iphdr *iph = (struct iphdr *)skb->data; +				struct iphdr *iph = ip_hdr(skb);  				iph->check = 0;  				ip_send_check(iph);  			}  		}  		if ((dext->flags & VNET_PKT_HCK_FULLCKSUM) && -		    skb->ip_summed == CHECKSUM_NONE) -			vnet_fullcsum(skb); +		    skb->ip_summed == CHECKSUM_NONE) { +			if (skb->protocol == htons(ETH_P_IP)) { +				struct iphdr *iph = ip_hdr(skb); +				int ihl = iph->ihl * 4; + +				skb_reset_transport_header(skb); +				skb_set_transport_header(skb, ihl); +				vnet_fullcsum(skb); +			} +		}  		if (dext->flags & VNET_PKT_HCK_IPV4_HDRCKSUM_OK) {  			skb->ip_summed = CHECKSUM_PARTIAL;  			skb->csum_level = 0; diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c index 70814b7386b3..af11ed1e0bcc 100644 --- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c +++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c @@ -426,7 +426,7 @@  #define DWC_MMC_RXOCTETCOUNT_GB          0x0784  #define DWC_MMC_RXPACKETCOUNT_GB         0x0780 -static int debug = 3; +static int debug = -1;  module_param(debug, int, 0);  MODULE_PARM_DESC(debug, "DWC_eth_qos debug level (0=none,...,16=all)"); @@ -650,6 +650,11 @@ struct net_local {  	u32 mmc_tx_counters_mask;  	struct dwceqos_flowcontrol flowcontrol; + +	/* Tracks the intermediate state of phy started but hardware +	 * init not finished yet. +	 */ +	bool phy_defer;  };  static void dwceqos_read_mmc_counters(struct net_local *lp, u32 rx_mask, @@ -901,6 +906,9 @@ static void dwceqos_adjust_link(struct net_device *ndev)  	struct phy_device *phydev = lp->phy_dev;  	int status_change = 0; +	if (lp->phy_defer) +		return; +  	if (phydev->link) {  		if ((lp->speed != phydev->speed) ||  		    (lp->duplex != phydev->duplex)) { @@ -1113,7 +1121,7 @@ static int dwceqos_descriptor_init(struct net_local *lp)  	/* Allocate DMA descriptors */  	size = DWCEQOS_RX_DCNT * sizeof(struct dwceqos_dma_desc);  	lp->rx_descs = dma_alloc_coherent(lp->ndev->dev.parent, size, -			&lp->rx_descs_addr, 0); +			&lp->rx_descs_addr, GFP_KERNEL);  	if (!lp->rx_descs)  		goto err_out;  	lp->rx_descs_tail_addr = lp->rx_descs_addr + @@ -1121,7 +1129,7 @@ static int dwceqos_descriptor_init(struct net_local *lp)  	size = DWCEQOS_TX_DCNT * sizeof(struct dwceqos_dma_desc);  	lp->tx_descs = dma_alloc_coherent(lp->ndev->dev.parent, size, -			&lp->tx_descs_addr, 0); +			&lp->tx_descs_addr, GFP_KERNEL);  	if (!lp->tx_descs)  		goto err_out;  	lp->tx_descs_tail_addr = lp->tx_descs_addr + @@ -1635,6 +1643,12 @@ static void dwceqos_init_hw(struct net_local *lp)  	regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG);  	dwceqos_write(lp, REG_DWCEQOS_MAC_CFG,  		      regval | DWCEQOS_MAC_CFG_TE | DWCEQOS_MAC_CFG_RE); + +	lp->phy_defer = false; +	mutex_lock(&lp->phy_dev->lock); +	phy_read_status(lp->phy_dev); +	dwceqos_adjust_link(lp->ndev); +	mutex_unlock(&lp->phy_dev->lock);  }  static void dwceqos_tx_reclaim(unsigned long data) @@ -1880,9 +1894,13 @@ static int dwceqos_open(struct net_device *ndev)  	}  	netdev_reset_queue(ndev); -	napi_enable(&lp->napi); +	/* The dwceqos reset state machine requires all phy clocks to complete, +	 * hence the unusual init order with phy_start first. +	 */ +	lp->phy_defer = true;  	phy_start(lp->phy_dev);  	dwceqos_init_hw(lp); +	napi_enable(&lp->napi);  	netif_start_queue(ndev);  	tasklet_enable(&lp->tx_bdreclaim_tasklet); @@ -1915,18 +1933,19 @@ static int dwceqos_stop(struct net_device *ndev)  {  	struct net_local *lp = netdev_priv(ndev); -	phy_stop(lp->phy_dev); -  	tasklet_disable(&lp->tx_bdreclaim_tasklet); -	netif_stop_queue(ndev);  	napi_disable(&lp->napi); -	dwceqos_drain_dma(lp); +	/* Stop all tx before we drain the tx dma. */ +	netif_tx_lock_bh(lp->ndev); +	netif_stop_queue(ndev); +	netif_tx_unlock_bh(lp->ndev); -	netif_tx_lock(lp->ndev); +	dwceqos_drain_dma(lp);  	dwceqos_reset_hw(lp); +	phy_stop(lp->phy_dev); +  	dwceqos_descriptor_free(lp); -	netif_tx_unlock(lp->ndev);  	return 0;  } @@ -2178,12 +2197,10 @@ static int dwceqos_start_xmit(struct sk_buff *skb, struct net_device *ndev)  		((trans.initial_descriptor + trans.nr_descriptors) %  		 DWCEQOS_TX_DCNT)); -	dwceqos_tx_finalize(skb, lp, &trans); - -	netdev_sent_queue(ndev, skb->len); -  	spin_lock_bh(&lp->tx_lock);  	lp->tx_free -= trans.nr_descriptors; +	dwceqos_tx_finalize(skb, lp, &trans); +	netdev_sent_queue(ndev, skb->len);  	spin_unlock_bh(&lp->tx_lock);  	ndev->trans_start = jiffies; diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c index e9cc61e1ec74..c3e85acfdc70 100644 --- a/drivers/net/ethernet/ti/cpsw-phy-sel.c +++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c @@ -63,8 +63,12 @@ static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv,  		mode = AM33XX_GMII_SEL_MODE_RGMII;  		break; -	case PHY_INTERFACE_MODE_MII:  	default: +		dev_warn(priv->dev, +			 "Unsupported PHY mode: \"%s\". Defaulting to MII.\n", +			phy_modes(phy_mode)); +		/* fallthrough */ +	case PHY_INTERFACE_MODE_MII:  		mode = AM33XX_GMII_SEL_MODE_MII;  		break;  	}; @@ -106,8 +110,12 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,  		mode = AM33XX_GMII_SEL_MODE_RGMII;  		break; -	case PHY_INTERFACE_MODE_MII:  	default: +		dev_warn(priv->dev, +			 "Unsupported PHY mode: \"%s\". Defaulting to MII.\n", +			phy_modes(phy_mode)); +		/* fallthrough */ +	case PHY_INTERFACE_MODE_MII:  		mode = AM33XX_GMII_SEL_MODE_MII;  		break;  	}; diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 657b65bf5cac..18bf3a8fdc50 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -82,7 +82,7 @@ struct cpdma_desc {  struct cpdma_desc_pool {  	phys_addr_t		phys; -	u32			hw_addr; +	dma_addr_t		hw_addr;  	void __iomem		*iomap;		/* ioremap map */  	void			*cpumap;	/* dma_alloc map */  	int			desc_size, mem_size; @@ -152,7 +152,7 @@ struct cpdma_chan {   * abstract out these details   */  static struct cpdma_desc_pool * -cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr, +cpdma_desc_pool_create(struct device *dev, u32 phys, dma_addr_t hw_addr,  				int size, int align)  {  	int bitmap_size; @@ -176,13 +176,13 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr,  	if (phys) {  		pool->phys  = phys; -		pool->iomap = ioremap(phys, size); +		pool->iomap = ioremap(phys, size); /* should be memremap? */  		pool->hw_addr = hw_addr;  	} else { -		pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys, +		pool->cpumap = dma_alloc_coherent(dev, size, &pool->hw_addr,  						  GFP_KERNEL); -		pool->iomap = pool->cpumap; -		pool->hw_addr = pool->phys; +		pool->iomap = (void __iomem __force *)pool->cpumap; +		pool->phys = pool->hw_addr; /* assumes no IOMMU, don't use this value */  	}  	if (pool->iomap) diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index c61d66d38634..029841f98c32 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -117,21 +117,17 @@ static void get_pkt_info(dma_addr_t *buff, u32 *buff_len, dma_addr_t *ndesc,  	*ndesc = le32_to_cpu(desc->next_desc);  } -static void get_pad_info(u32 *pad0, u32 *pad1, u32 *pad2, struct knav_dma_desc *desc) +static u32 get_sw_data(int index, struct knav_dma_desc *desc)  { -	*pad0 = le32_to_cpu(desc->pad[0]); -	*pad1 = le32_to_cpu(desc->pad[1]); -	*pad2 = le32_to_cpu(desc->pad[2]); +	/* No Endian conversion needed as this data is untouched by hw */ +	return desc->sw_data[index];  } -static void get_pad_ptr(void **padptr, struct knav_dma_desc *desc) -{ -	u64 pad64; - -	pad64 = le32_to_cpu(desc->pad[0]) + -		((u64)le32_to_cpu(desc->pad[1]) << 32); -	*padptr = (void *)(uintptr_t)pad64; -} +/* use these macros to get sw data */ +#define GET_SW_DATA0(desc) get_sw_data(0, desc) +#define GET_SW_DATA1(desc) get_sw_data(1, desc) +#define GET_SW_DATA2(desc) get_sw_data(2, desc) +#define GET_SW_DATA3(desc) get_sw_data(3, desc)  static void get_org_pkt_info(dma_addr_t *buff, u32 *buff_len,  			     struct knav_dma_desc *desc) @@ -163,13 +159,18 @@ static void set_desc_info(u32 desc_info, u32 pkt_info,  	desc->packet_info = cpu_to_le32(pkt_info);  } -static void set_pad_info(u32 pad0, u32 pad1, u32 pad2, struct knav_dma_desc *desc) +static void set_sw_data(int index, u32 data, struct knav_dma_desc *desc)  { -	desc->pad[0] = cpu_to_le32(pad0); -	desc->pad[1] = cpu_to_le32(pad1); -	desc->pad[2] = cpu_to_le32(pad1); +	/* No Endian conversion needed as this data is untouched by hw */ +	desc->sw_data[index] = data;  } +/* use these macros to set sw data */ +#define SET_SW_DATA0(data, desc) set_sw_data(0, data, desc) +#define SET_SW_DATA1(data, desc) set_sw_data(1, data, desc) +#define SET_SW_DATA2(data, desc) set_sw_data(2, data, desc) +#define SET_SW_DATA3(data, desc) set_sw_data(3, data, desc) +  static void set_org_pkt_info(dma_addr_t buff, u32 buff_len,  			     struct knav_dma_desc *desc)  { @@ -581,7 +582,6 @@ static void netcp_free_rx_desc_chain(struct netcp_intf *netcp,  	dma_addr_t dma_desc, dma_buf;  	unsigned int buf_len, dma_sz = sizeof(*ndesc);  	void *buf_ptr; -	u32 pad[2];  	u32 tmp;  	get_words(&dma_desc, 1, &desc->next_desc); @@ -593,14 +593,20 @@ static void netcp_free_rx_desc_chain(struct netcp_intf *netcp,  			break;  		}  		get_pkt_info(&dma_buf, &tmp, &dma_desc, ndesc); -		get_pad_ptr(&buf_ptr, ndesc); +		/* warning!!!! We are retrieving the virtual ptr in the sw_data +		 * field as a 32bit value. Will not work on 64bit machines +		 */ +		buf_ptr = (void *)GET_SW_DATA0(ndesc); +		buf_len = (int)GET_SW_DATA1(desc);  		dma_unmap_page(netcp->dev, dma_buf, PAGE_SIZE, DMA_FROM_DEVICE);  		__free_page(buf_ptr);  		knav_pool_desc_put(netcp->rx_pool, desc);  	} - -	get_pad_info(&pad[0], &pad[1], &buf_len, desc); -	buf_ptr = (void *)(uintptr_t)(pad[0] + ((u64)pad[1] << 32)); +	/* warning!!!! We are retrieving the virtual ptr in the sw_data +	 * field as a 32bit value. Will not work on 64bit machines +	 */ +	buf_ptr = (void *)GET_SW_DATA0(desc); +	buf_len = (int)GET_SW_DATA1(desc);  	if (buf_ptr)  		netcp_frag_free(buf_len <= PAGE_SIZE, buf_ptr); @@ -639,7 +645,6 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)  	dma_addr_t dma_desc, dma_buff;  	struct netcp_packet p_info;  	struct sk_buff *skb; -	u32 pad[2];  	void *org_buf_ptr;  	dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz); @@ -653,8 +658,11 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)  	}  	get_pkt_info(&dma_buff, &buf_len, &dma_desc, desc); -	get_pad_info(&pad[0], &pad[1], &org_buf_len, desc); -	org_buf_ptr = (void *)(uintptr_t)(pad[0] + ((u64)pad[1] << 32)); +	/* warning!!!! We are retrieving the virtual ptr in the sw_data +	 * field as a 32bit value. Will not work on 64bit machines +	 */ +	org_buf_ptr = (void *)GET_SW_DATA0(desc); +	org_buf_len = (int)GET_SW_DATA1(desc);  	if (unlikely(!org_buf_ptr)) {  		dev_err(netcp->ndev_dev, "NULL bufptr in desc\n"); @@ -679,7 +687,6 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)  	/* Fill in the page fragment list */  	while (dma_desc) {  		struct page *page; -		void *ptr;  		ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz);  		if (unlikely(!ndesc)) { @@ -688,8 +695,10 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)  		}  		get_pkt_info(&dma_buff, &buf_len, &dma_desc, ndesc); -		get_pad_ptr(&ptr, ndesc); -		page = ptr; +		/* warning!!!! We are retrieving the virtual ptr in the sw_data +		 * field as a 32bit value. Will not work on 64bit machines +		 */ +		page = (struct page *)GET_SW_DATA0(desc);  		if (likely(dma_buff && buf_len && page)) {  			dma_unmap_page(netcp->dev, dma_buff, PAGE_SIZE, @@ -777,7 +786,10 @@ static void netcp_free_rx_buf(struct netcp_intf *netcp, int fdq)  		}  		get_org_pkt_info(&dma, &buf_len, desc); -		get_pad_ptr(&buf_ptr, desc); +		/* warning!!!! We are retrieving the virtual ptr in the sw_data +		 * field as a 32bit value. Will not work on 64bit machines +		 */ +		buf_ptr = (void *)GET_SW_DATA0(desc);  		if (unlikely(!dma)) {  			dev_err(netcp->ndev_dev, "NULL orig_buff in desc\n"); @@ -829,7 +841,7 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)  	struct page *page;  	dma_addr_t dma;  	void *bufptr; -	u32 pad[3]; +	u32 sw_data[2];  	/* Allocate descriptor */  	hwdesc = knav_pool_desc_get(netcp->rx_pool); @@ -846,7 +858,7 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)  				SKB_DATA_ALIGN(sizeof(struct skb_shared_info));  		bufptr = netdev_alloc_frag(primary_buf_len); -		pad[2] = primary_buf_len; +		sw_data[1] = primary_buf_len;  		if (unlikely(!bufptr)) {  			dev_warn_ratelimited(netcp->ndev_dev, @@ -858,9 +870,10 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)  		if (unlikely(dma_mapping_error(netcp->dev, dma)))  			goto fail; -		pad[0] = lower_32_bits((uintptr_t)bufptr); -		pad[1] = upper_32_bits((uintptr_t)bufptr); - +		/* warning!!!! We are saving the virtual ptr in the sw_data +		 * field as a 32bit value. Will not work on 64bit machines +		 */ +		sw_data[0] = (u32)bufptr;  	} else {  		/* Allocate a secondary receive queue entry */  		page = alloc_page(GFP_ATOMIC | GFP_DMA | __GFP_COLD); @@ -870,9 +883,11 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)  		}  		buf_len = PAGE_SIZE;  		dma = dma_map_page(netcp->dev, page, 0, buf_len, DMA_TO_DEVICE); -		pad[0] = lower_32_bits(dma); -		pad[1] = upper_32_bits(dma); -		pad[2] = 0; +		/* warning!!!! We are saving the virtual ptr in the sw_data +		 * field as a 32bit value. Will not work on 64bit machines +		 */ +		sw_data[0] = (u32)page; +		sw_data[1] = 0;  	}  	desc_info =  KNAV_DMA_DESC_PS_INFO_IN_DESC; @@ -882,7 +897,8 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)  	pkt_info |= (netcp->rx_queue_id & KNAV_DMA_DESC_RETQ_MASK) <<  		    KNAV_DMA_DESC_RETQ_SHIFT;  	set_org_pkt_info(dma, buf_len, hwdesc); -	set_pad_info(pad[0], pad[1], pad[2], hwdesc); +	SET_SW_DATA0(sw_data[0], hwdesc); +	SET_SW_DATA1(sw_data[1], hwdesc);  	set_desc_info(desc_info, pkt_info, hwdesc);  	/* Push to FDQs */ @@ -971,7 +987,6 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,  					  unsigned int budget)  {  	struct knav_dma_desc *desc; -	void *ptr;  	struct sk_buff *skb;  	unsigned int dma_sz;  	dma_addr_t dma; @@ -988,8 +1003,10 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,  			continue;  		} -		get_pad_ptr(&ptr, desc); -		skb = ptr; +		/* warning!!!! We are retrieving the virtual ptr in the sw_data +		 * field as a 32bit value. Will not work on 64bit machines +		 */ +		skb = (struct sk_buff *)GET_SW_DATA0(desc);  		netcp_free_tx_desc_chain(netcp, desc, dma_sz);  		if (!skb) {  			dev_err(netcp->ndev_dev, "No skb in Tx desc\n"); @@ -1194,10 +1211,10 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,  	}  	set_words(&tmp, 1, &desc->packet_info); -	tmp = lower_32_bits((uintptr_t)&skb); -	set_words(&tmp, 1, &desc->pad[0]); -	tmp = upper_32_bits((uintptr_t)&skb); -	set_words(&tmp, 1, &desc->pad[1]); +	/* warning!!!! We are saving the virtual ptr in the sw_data +	 * field as a 32bit value. Will not work on 64bit machines +	 */ +	SET_SW_DATA0((u32)skb, desc);  	if (tx_pipe->flags & SWITCH_TO_PORT_IN_TAGINFO) {  		tmp = tx_pipe->switch_to_port; diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c index 3c54a2cae5df..67610270d171 100644 --- a/drivers/net/ethernet/toshiba/spider_net.c +++ b/drivers/net/ethernet/toshiba/spider_net.c @@ -48,7 +48,6 @@  #include <linux/wait.h>  #include <linux/workqueue.h>  #include <linux/bitops.h> -#include <asm/pci-bridge.h>  #include <net/checksum.h>  #include "spider_net.h" diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 7f975a2c8990..b0de8ecd7fe8 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -533,8 +533,8 @@ static int dfx_register(struct device *bdev)  	const char *print_name = dev_name(bdev);  	struct net_device *dev;  	DFX_board_t	  *bp;			/* board pointer */ -	resource_size_t bar_start[3];		/* pointers to ports */ -	resource_size_t bar_len[3];		/* resource length */ +	resource_size_t bar_start[3] = {0};	/* pointers to ports */ +	resource_size_t bar_len[3] = {0};	/* resource length */  	int alloc_size;				/* total buffer size used */  	struct resource *region;  	int err = 0; @@ -3697,8 +3697,8 @@ static void dfx_unregister(struct device *bdev)  	int dfx_bus_pci = dev_is_pci(bdev);  	int dfx_bus_tc = DFX_BUS_TC(bdev);  	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; -	resource_size_t bar_start[3];		/* pointers to ports */ -	resource_size_t bar_len[3];		/* resource lengths */ +	resource_size_t bar_start[3] = {0};	/* pointers to ports */ +	resource_size_t bar_len[3] = {0};	/* resource lengths */  	int		alloc_size;		/* total buffer size used */  	unregister_netdev(dev); diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 7456569f53c1..0bf7edd99573 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -980,9 +980,9 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,  			opts = ip_tunnel_info_opts(info);  		if (key->tun_flags & TUNNEL_CSUM) -			flags |= GENEVE_F_UDP_CSUM; +			flags &= ~GENEVE_F_UDP_ZERO_CSUM6_TX;  		else -			flags &= ~GENEVE_F_UDP_CSUM; +			flags |= GENEVE_F_UDP_ZERO_CSUM6_TX;  		err = geneve6_build_skb(dst, skb, key->tun_flags, vni,  					info->options_len, opts, @@ -1039,6 +1039,34 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)  	return geneve_xmit_skb(skb, dev, info);  } +static int __geneve_change_mtu(struct net_device *dev, int new_mtu, bool strict) +{ +	/* The max_mtu calculation does not take account of GENEVE +	 * options, to avoid excluding potentially valid +	 * configurations. +	 */ +	int max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - sizeof(struct iphdr) +		- dev->hard_header_len; + +	if (new_mtu < 68) +		return -EINVAL; + +	if (new_mtu > max_mtu) { +		if (strict) +			return -EINVAL; + +		new_mtu = max_mtu; +	} + +	dev->mtu = new_mtu; +	return 0; +} + +static int geneve_change_mtu(struct net_device *dev, int new_mtu) +{ +	return __geneve_change_mtu(dev, new_mtu, true); +} +  static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)  {  	struct ip_tunnel_info *info = skb_tunnel_info(skb); @@ -1083,7 +1111,7 @@ static const struct net_device_ops geneve_netdev_ops = {  	.ndo_stop		= geneve_stop,  	.ndo_start_xmit		= geneve_xmit,  	.ndo_get_stats64	= ip_tunnel_get_stats64, -	.ndo_change_mtu		= eth_change_mtu, +	.ndo_change_mtu		= geneve_change_mtu,  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_set_mac_address	= eth_mac_addr,  	.ndo_fill_metadata_dst	= geneve_fill_metadata_dst, @@ -1150,6 +1178,7 @@ static void geneve_setup(struct net_device *dev)  	dev->hw_features |= NETIF_F_GSO_SOFTWARE;  	netif_keep_dst(dev); +	dev->priv_flags &= ~IFF_TX_SKB_SHARING;  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;  	eth_hw_addr_random(dev);  } @@ -1441,12 +1470,23 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,  		return dev;  	err = geneve_configure(net, dev, &geneve_remote_unspec, -			       0, 0, 0, htons(dst_port), true, 0); -	if (err) { -		free_netdev(dev); -		return ERR_PTR(err); -	} +			       0, 0, 0, htons(dst_port), true, +			       GENEVE_F_UDP_ZERO_CSUM6_RX); +	if (err) +		goto err; + +	/* openvswitch users expect packet sizes to be unrestricted, +	 * so set the largest MTU we can. +	 */ +	err = __geneve_change_mtu(dev, IP_MAX_MTU, false); +	if (err) +		goto err; +  	return dev; + + err: +	free_netdev(dev); +	return ERR_PTR(err);  }  EXPORT_SYMBOL_GPL(geneve_dev_create_fb); diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index f4130af09244..fcb92c0d0eb9 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -624,6 +624,7 @@ struct nvsp_message {  #define RNDIS_PKT_ALIGN_DEFAULT 8  struct multi_send_data { +	struct sk_buff *skb; /* skb containing the pkt */  	struct hv_netvsc_packet *pkt; /* netvsc pkt pending */  	u32 count; /* counter of batched packets */  }; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 059fc5231601..ec313fc08d82 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -841,6 +841,18 @@ static inline int netvsc_send_pkt(  	return ret;  } +/* Move packet out of multi send data (msd), and clear msd */ +static inline void move_pkt_msd(struct hv_netvsc_packet **msd_send, +				struct sk_buff **msd_skb, +				struct multi_send_data *msdp) +{ +	*msd_skb = msdp->skb; +	*msd_send = msdp->pkt; +	msdp->skb = NULL; +	msdp->pkt = NULL; +	msdp->count = 0; +} +  int netvsc_send(struct hv_device *device,  		struct hv_netvsc_packet *packet,  		struct rndis_message *rndis_msg, @@ -855,6 +867,7 @@ int netvsc_send(struct hv_device *device,  	unsigned int section_index = NETVSC_INVALID_INDEX;  	struct multi_send_data *msdp;  	struct hv_netvsc_packet *msd_send = NULL, *cur_send = NULL; +	struct sk_buff *msd_skb = NULL;  	bool try_batch;  	bool xmit_more = (skb != NULL) ? skb->xmit_more : false; @@ -897,10 +910,8 @@ int netvsc_send(struct hv_device *device,  		   net_device->send_section_size) {  		section_index = netvsc_get_next_send_section(net_device);  		if (section_index != NETVSC_INVALID_INDEX) { -				msd_send = msdp->pkt; -				msdp->pkt = NULL; -				msdp->count = 0; -				msd_len = 0; +			move_pkt_msd(&msd_send, &msd_skb, msdp); +			msd_len = 0;  		}  	} @@ -919,31 +930,31 @@ int netvsc_send(struct hv_device *device,  			packet->total_data_buflen += msd_len;  		} -		if (msdp->pkt) -			dev_kfree_skb_any(skb); +		if (msdp->skb) +			dev_kfree_skb_any(msdp->skb);  		if (xmit_more && !packet->cp_partial) { +			msdp->skb = skb;  			msdp->pkt = packet;  			msdp->count++;  		} else {  			cur_send = packet; +			msdp->skb = NULL;  			msdp->pkt = NULL;  			msdp->count = 0;  		}  	} else { -		msd_send = msdp->pkt; -		msdp->pkt = NULL; -		msdp->count = 0; +		move_pkt_msd(&msd_send, &msd_skb, msdp);  		cur_send = packet;  	}  	if (msd_send) { -		m_ret = netvsc_send_pkt(msd_send, net_device, pb, skb); +		m_ret = netvsc_send_pkt(msd_send, net_device, NULL, msd_skb);  		if (m_ret != 0) {  			netvsc_free_send_slot(net_device,  					      msd_send->send_buf_index); -			dev_kfree_skb_any(skb); +			dev_kfree_skb_any(msd_skb);  		}  	} diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 1c8db9afdcda..98e34fee45c7 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -196,65 +196,6 @@ static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,  	return ppi;  } -union sub_key { -	u64 k; -	struct { -		u8 pad[3]; -		u8 kb; -		u32 ka; -	}; -}; - -/* Toeplitz hash function - * data: network byte order - * return: host byte order - */ -static u32 comp_hash(u8 *key, int klen, void *data, int dlen) -{ -	union sub_key subk; -	int k_next = 4; -	u8 dt; -	int i, j; -	u32 ret = 0; - -	subk.k = 0; -	subk.ka = ntohl(*(u32 *)key); - -	for (i = 0; i < dlen; i++) { -		subk.kb = key[k_next]; -		k_next = (k_next + 1) % klen; -		dt = ((u8 *)data)[i]; -		for (j = 0; j < 8; j++) { -			if (dt & 0x80) -				ret ^= subk.ka; -			dt <<= 1; -			subk.k <<= 1; -		} -	} - -	return ret; -} - -static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb) -{ -	struct flow_keys flow; -	int data_len; - -	if (!skb_flow_dissect_flow_keys(skb, &flow, 0) || -	    !(flow.basic.n_proto == htons(ETH_P_IP) || -	      flow.basic.n_proto == htons(ETH_P_IPV6))) -		return false; - -	if (flow.basic.ip_proto == IPPROTO_TCP) -		data_len = 12; -	else -		data_len = 8; - -	*hash = comp_hash(netvsc_hash_key, HASH_KEYLEN, &flow, data_len); - -	return true; -} -  static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,  			void *accel_priv, select_queue_fallback_t fallback)  { @@ -267,11 +208,9 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,  	if (nvsc_dev == NULL || ndev->real_num_tx_queues <= 1)  		return 0; -	if (netvsc_set_hash(&hash, skb)) { -		q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] % -			ndev->real_num_tx_queues; -		skb_set_hash(skb, hash, PKT_HASH_TYPE_L3); -	} +	hash = skb_get_hash(skb); +	q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] % +		ndev->real_num_tx_queues;  	if (!nvsc_dev->chn_table[q_idx])  		q_idx = 0; @@ -1150,6 +1089,9 @@ static int netvsc_probe(struct hv_device *dev,  	net->ethtool_ops = ðtool_ops;  	SET_NETDEV_DEV(net, &dev->device); +	/* We always need headroom for rndis header */ +	net->needed_headroom = RNDIS_AND_PPI_SIZE; +  	/* Notify the netvsc driver of the new device */  	memset(&device_info, 0, sizeof(device_info));  	device_info.ring_size = ring_size; diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h index 29cbde8501ed..d47cf14bb4a5 100644 --- a/drivers/net/irda/bfin_sir.h +++ b/drivers/net/irda/bfin_sir.h @@ -82,9 +82,6 @@ struct bfin_sir_self {  #define DRIVER_NAME "bfin_sir" -#define port_membase(port)     (((struct bfin_sir_port *)(port))->membase) -#define get_lsr_cache(port)    (((struct bfin_sir_port *)(port))->lsr) -#define put_lsr_cache(port, v) (((struct bfin_sir_port *)(port))->lsr = (v))  #include <asm/bfin_serial.h>  static const unsigned short per[][4] = { diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 696852eb23c3..7a3f990c1935 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -430,16 +430,6 @@ static int irtty_open(struct tty_struct *tty)  	/* Module stuff handled via irda_ldisc.owner - Jean II */ -	/* First make sure we're not already connected. */ -	if (tty->disc_data != NULL) { -		priv = tty->disc_data; -		if (priv && priv->magic == IRTTY_MAGIC) { -			ret = -EEXIST; -			goto out; -		} -		tty->disc_data = NULL;		/* ### */ -	} -  	/* stop the underlying  driver */  	irtty_stop_receiver(tty, TRUE);  	if (tty->ops->stop) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 6a57a005e0ca..94e688805dd2 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1323,6 +1323,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,  	list_add_tail_rcu(&vlan->list, &port->vlans);  	netif_stacked_transfer_operstate(lowerdev, dev); +	linkwatch_fire_event(dev);  	return 0; @@ -1522,6 +1523,7 @@ static int macvlan_device_event(struct notifier_block *unused,  	port = macvlan_port_get_rtnl(dev);  	switch (event) { +	case NETDEV_UP:  	case NETDEV_CHANGE:  		list_for_each_entry(vlan, &port->vlans, list)  			netif_stacked_transfer_operstate(vlan->lowerdev, diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 60994a83a0d6..f0a77020037a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -186,6 +186,7 @@ config MDIO_GPIO  config MDIO_OCTEON  	tristate "Support for MDIO buses on Octeon and ThunderX SOCs"  	depends on 64BIT +	depends on HAS_IOMEM  	help  	  This module provides a driver for the Octeon and ThunderX MDIO diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index bf241a3ec5e5..db507e3bcab9 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -250,10 +250,6 @@ static int bcm7xxx_config_init(struct phy_device *phydev)  	phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);  	phy_read(phydev, MII_BCM7XXX_AUX_MODE); -	/* Workaround only required for 100Mbits/sec capable PHYs */ -	if (phydev->supported & PHY_GBIT_FEATURES) -		return 0; -  	/* set shadow mode 2 */  	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,  			MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); @@ -270,7 +266,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev)  	phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);  	/* reset shadow mode 2 */ -	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0); +	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);  	if (ret < 0)  		return ret; @@ -307,11 +303,6 @@ static int bcm7xxx_suspend(struct phy_device *phydev)  	return 0;  } -static int bcm7xxx_dummy_config_init(struct phy_device *phydev) -{ -	return 0; -} -  #define BCM7XXX_28NM_GPHY(_oui, _name)					\  {									\  	.phy_id		= (_oui),					\ @@ -337,7 +328,7 @@ static struct phy_driver bcm7xxx_driver[] = {  	.phy_id         = PHY_ID_BCM7425,  	.phy_id_mask    = 0xfffffff0,  	.name           = "Broadcom BCM7425", -	.features       = PHY_GBIT_FEATURES | +	.features       = PHY_BASIC_FEATURES |  			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,  	.flags          = PHY_IS_INTERNAL,  	.config_init    = bcm7xxx_config_init, @@ -349,7 +340,7 @@ static struct phy_driver bcm7xxx_driver[] = {  	.phy_id         = PHY_ID_BCM7429,  	.phy_id_mask    = 0xfffffff0,  	.name           = "Broadcom BCM7429", -	.features       = PHY_GBIT_FEATURES | +	.features       = PHY_BASIC_FEATURES |  			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,  	.flags          = PHY_IS_INTERNAL,  	.config_init    = bcm7xxx_config_init, @@ -361,7 +352,7 @@ static struct phy_driver bcm7xxx_driver[] = {  	.phy_id         = PHY_ID_BCM7435,  	.phy_id_mask    = 0xfffffff0,  	.name           = "Broadcom BCM7435", -	.features       = PHY_GBIT_FEATURES | +	.features       = PHY_BASIC_FEATURES |  			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,  	.flags          = PHY_IS_INTERNAL,  	.config_init    = bcm7xxx_config_init, @@ -369,30 +360,6 @@ static struct phy_driver bcm7xxx_driver[] = {  	.read_status    = genphy_read_status,  	.suspend        = bcm7xxx_suspend,  	.resume         = bcm7xxx_config_init, -}, { -	.phy_id		= PHY_BCM_OUI_4, -	.phy_id_mask	= 0xffff0000, -	.name		= "Broadcom BCM7XXX 40nm", -	.features	= PHY_GBIT_FEATURES | -			  SUPPORTED_Pause | SUPPORTED_Asym_Pause, -	.flags		= PHY_IS_INTERNAL, -	.config_init	= bcm7xxx_config_init, -	.config_aneg	= genphy_config_aneg, -	.read_status	= genphy_read_status, -	.suspend	= bcm7xxx_suspend, -	.resume		= bcm7xxx_config_init, -}, { -	.phy_id		= PHY_BCM_OUI_5, -	.phy_id_mask	= 0xffffff00, -	.name		= "Broadcom BCM7XXX 65nm", -	.features	= PHY_BASIC_FEATURES | -			  SUPPORTED_Pause | SUPPORTED_Asym_Pause, -	.flags		= PHY_IS_INTERNAL, -	.config_init	= bcm7xxx_dummy_config_init, -	.config_aneg	= genphy_config_aneg, -	.read_status	= genphy_read_status, -	.suspend	= bcm7xxx_suspend, -	.resume		= bcm7xxx_config_init,  } };  static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { @@ -404,8 +371,6 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {  	{ PHY_ID_BCM7439, 0xfffffff0, },  	{ PHY_ID_BCM7435, 0xfffffff0, },  	{ PHY_ID_BCM7445, 0xfffffff0, }, -	{ PHY_BCM_OUI_4, 0xffff0000 }, -	{ PHY_BCM_OUI_5, 0xffffff00 },  	{ }  }; diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 180f69952779..7a240fce3a7e 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -846,6 +846,11 @@ static void decode_rxts(struct dp83640_private *dp83640,  	struct skb_shared_hwtstamps *shhwtstamps = NULL;  	struct sk_buff *skb;  	unsigned long flags; +	u8 overflow; + +	overflow = (phy_rxts->ns_hi >> 14) & 0x3; +	if (overflow) +		pr_debug("rx timestamp queue overflow, count %d\n", overflow);  	spin_lock_irqsave(&dp83640->rx_lock, flags); @@ -888,6 +893,7 @@ static void decode_txts(struct dp83640_private *dp83640,  	struct skb_shared_hwtstamps shhwtstamps;  	struct sk_buff *skb;  	u64 ns; +	u8 overflow;  	/* We must already have the skb that triggered this. */ @@ -897,6 +903,17 @@ static void decode_txts(struct dp83640_private *dp83640,  		pr_debug("have timestamp but tx_queue empty\n");  		return;  	} + +	overflow = (phy_txts->ns_hi >> 14) & 0x3; +	if (overflow) { +		pr_debug("tx timestamp queue overflow, count %d\n", overflow); +		while (skb) { +			skb_complete_tx_timestamp(skb, NULL); +			skb = skb_dequeue(&dp83640->tx_queue); +		} +		return; +	} +  	ns = phy2txts(phy_txts);  	memset(&shhwtstamps, 0, sizeof(shhwtstamps));  	shhwtstamps.hwtstamp = ns_to_ktime(ns); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index e3eb96443c97..ab1d0fcaf1d9 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -446,6 +446,12 @@ static int m88e1510_config_aneg(struct phy_device *phydev)  	if (err < 0)  		return err; +	return 0; +} + +static int marvell_config_init(struct phy_device *phydev) +{ +	/* Set registers from marvell,reg-init DT property */  	return marvell_of_reg_init(phydev);  } @@ -495,7 +501,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)  	mdelay(500); -	return 0; +	return marvell_config_init(phydev);  }  static int m88e3016_config_init(struct phy_device *phydev) @@ -514,7 +520,7 @@ static int m88e3016_config_init(struct phy_device *phydev)  	if (reg < 0)  		return reg; -	return 0; +	return marvell_config_init(phydev);  }  static int m88e1111_config_init(struct phy_device *phydev) @@ -1078,6 +1084,7 @@ static struct phy_driver marvell_drivers[] = {  		.features = PHY_GBIT_FEATURES,  		.probe = marvell_probe,  		.flags = PHY_HAS_INTERRUPT, +		.config_init = &marvell_config_init,  		.config_aneg = &marvell_config_aneg,  		.read_status = &genphy_read_status,  		.ack_interrupt = &marvell_ack_interrupt, @@ -1149,6 +1156,7 @@ static struct phy_driver marvell_drivers[] = {  		.features = PHY_GBIT_FEATURES,  		.flags = PHY_HAS_INTERRUPT,  		.probe = marvell_probe, +		.config_init = &marvell_config_init,  		.config_aneg = &m88e1121_config_aneg,  		.read_status = &marvell_read_status,  		.ack_interrupt = &marvell_ack_interrupt, @@ -1167,6 +1175,7 @@ static struct phy_driver marvell_drivers[] = {  		.features = PHY_GBIT_FEATURES,  		.flags = PHY_HAS_INTERRUPT,  		.probe = marvell_probe, +		.config_init = &marvell_config_init,  		.config_aneg = &m88e1318_config_aneg,  		.read_status = &marvell_read_status,  		.ack_interrupt = &marvell_ack_interrupt, @@ -1259,6 +1268,7 @@ static struct phy_driver marvell_drivers[] = {  		.features = PHY_GBIT_FEATURES,  		.flags = PHY_HAS_INTERRUPT,  		.probe = marvell_probe, +		.config_init = &marvell_config_init,  		.config_aneg = &m88e1510_config_aneg,  		.read_status = &marvell_read_status,  		.ack_interrupt = &marvell_ack_interrupt, @@ -1277,6 +1287,7 @@ static struct phy_driver marvell_drivers[] = {  		.features = PHY_GBIT_FEATURES,  		.flags = PHY_HAS_INTERRUPT,  		.probe = marvell_probe, +		.config_init = &marvell_config_init,  		.config_aneg = &m88e1510_config_aneg,  		.read_status = &marvell_read_status,  		.ack_interrupt = &marvell_ack_interrupt, diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 03833dbfca67..dc85f7095e51 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -297,6 +297,17 @@ static int kszphy_config_init(struct phy_device *phydev)  	if (priv->led_mode >= 0)  		kszphy_setup_led(phydev, type->led_mode_reg, priv->led_mode); +	if (phy_interrupt_is_valid(phydev)) { +		int ctl = phy_read(phydev, MII_BMCR); + +		if (ctl < 0) +			return ctl; + +		ret = phy_write(phydev, MII_BMCR, ctl & ~BMCR_ANENABLE); +		if (ret < 0) +			return ret; +	} +  	return 0;  } @@ -635,6 +646,21 @@ static void kszphy_get_stats(struct phy_device *phydev,  		data[i] = kszphy_get_stat(phydev, i);  } +static int kszphy_resume(struct phy_device *phydev) +{ +	int value; + +	mutex_lock(&phydev->lock); + +	value = phy_read(phydev, MII_BMCR); +	phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); + +	kszphy_config_intr(phydev); +	mutex_unlock(&phydev->lock); + +	return 0; +} +  static int kszphy_probe(struct phy_device *phydev)  {  	const struct kszphy_type *type = phydev->drv->driver_data; @@ -844,7 +870,7 @@ static struct phy_driver ksphy_driver[] = {  	.get_strings	= kszphy_get_strings,  	.get_stats	= kszphy_get_stats,  	.suspend	= genphy_suspend, -	.resume		= genphy_resume, +	.resume		= kszphy_resume,  }, {  	.phy_id		= PHY_ID_KSZ8061,  	.name		= "Micrel KSZ8061", diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 8763bb20988a..5590b9c182c9 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -692,25 +692,29 @@ void phy_change(struct work_struct *work)  	struct phy_device *phydev =  		container_of(work, struct phy_device, phy_queue); -	if (phydev->drv->did_interrupt && -	    !phydev->drv->did_interrupt(phydev)) -		goto ignore; +	if (phy_interrupt_is_valid(phydev)) { +		if (phydev->drv->did_interrupt && +		    !phydev->drv->did_interrupt(phydev)) +			goto ignore; -	if (phy_disable_interrupts(phydev)) -		goto phy_err; +		if (phy_disable_interrupts(phydev)) +			goto phy_err; +	}  	mutex_lock(&phydev->lock);  	if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))  		phydev->state = PHY_CHANGELINK;  	mutex_unlock(&phydev->lock); -	atomic_dec(&phydev->irq_disable); -	enable_irq(phydev->irq); +	if (phy_interrupt_is_valid(phydev)) { +		atomic_dec(&phydev->irq_disable); +		enable_irq(phydev->irq); -	/* Reenable interrupts */ -	if (PHY_HALTED != phydev->state && -	    phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED)) -		goto irq_enable_err; +		/* Reenable interrupts */ +		if (PHY_HALTED != phydev->state && +		    phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED)) +			goto irq_enable_err; +	}  	/* reschedule state queue work to run as soon as possible */  	cancel_delayed_work_sync(&phydev->state_queue); @@ -905,10 +909,10 @@ void phy_state_machine(struct work_struct *work)  		phydev->adjust_link(phydev->attached_dev);  		break;  	case PHY_RUNNING: -		/* Only register a CHANGE if we are polling or ignoring -		 * interrupts and link changed since latest checking. +		/* Only register a CHANGE if we are polling and link changed +		 * since latest checking.  		 */ -		if (!phy_interrupt_is_valid(phydev)) { +		if (phydev->irq == PHY_POLL) {  			old_link = phydev->link;  			err = phy_read_status(phydev);  			if (err) @@ -1000,15 +1004,21 @@ void phy_state_machine(struct work_struct *work)  		   phy_state_to_str(old_state),  		   phy_state_to_str(phydev->state)); -	queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, -			   PHY_STATE_TIME * HZ); +	/* Only re-schedule a PHY state machine change if we are polling the +	 * PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving +	 * between states from phy_mac_interrupt() +	 */ +	if (phydev->irq == PHY_POLL) +		queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, +				   PHY_STATE_TIME * HZ);  }  void phy_mac_interrupt(struct phy_device *phydev, int new_link)  { -	cancel_work_sync(&phydev->phy_queue);  	phydev->link = new_link; -	schedule_work(&phydev->phy_queue); + +	/* Trigger a state machine change */ +	queue_work(system_power_efficient_wq, &phydev->phy_queue);  }  EXPORT_SYMBOL(phy_mac_interrupt); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index bad3f005faee..e551f3a89cfd 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1410,7 +1410,7 @@ int genphy_config_init(struct phy_device *phydev)  	features = (SUPPORTED_TP | SUPPORTED_MII  			| SUPPORTED_AUI | SUPPORTED_FIBRE | -			SUPPORTED_BNC); +			SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause);  	/* Do we support autonegotiation? */  	val = phy_read(phydev, MII_BMSR); diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index e485f2653c82..2e21e9366f76 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -24,6 +24,10 @@  #include <linux/netdevice.h>  #include <linux/smscphy.h> +struct smsc_phy_priv { +	bool energy_enable; +}; +  static int smsc_phy_config_intr(struct phy_device *phydev)  {  	int rc = phy_write (phydev, MII_LAN83C185_IM, @@ -43,19 +47,14 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev)  static int smsc_phy_config_init(struct phy_device *phydev)  { -	int __maybe_unused len; -	struct device *dev __maybe_unused = &phydev->mdio.dev; -	struct device_node *of_node __maybe_unused = dev->of_node; +	struct smsc_phy_priv *priv = phydev->priv; +  	int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); -	int enable_energy = 1;  	if (rc < 0)  		return rc; -	if (of_find_property(of_node, "smsc,disable-energy-detect", &len)) -		enable_energy = 0; - -	if (enable_energy) { +	if (priv->energy_enable) {  		/* Enable energy detect mode for this SMSC Transceivers */  		rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,  			       rc | MII_LAN83C185_EDPWRDOWN); @@ -110,10 +109,13 @@ static int lan911x_config_init(struct phy_device *phydev)   */  static int lan87xx_read_status(struct phy_device *phydev)  { +	struct smsc_phy_priv *priv = phydev->priv; +  	int err = genphy_read_status(phydev); -	int i; -	if (!phydev->link) { +	if (!phydev->link && priv->energy_enable) { +		int i; +  		/* Disable EDPD to wake up PHY */  		int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);  		if (rc < 0) @@ -149,6 +151,26 @@ static int lan87xx_read_status(struct phy_device *phydev)  	return err;  } +static int smsc_phy_probe(struct phy_device *phydev) +{ +	struct device *dev = &phydev->mdio.dev; +	struct device_node *of_node = dev->of_node; +	struct smsc_phy_priv *priv; + +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	priv->energy_enable = true; + +	if (of_property_read_bool(of_node, "smsc,disable-energy-detect")) +		priv->energy_enable = false; + +	phydev->priv = priv; + +	return 0; +} +  static struct phy_driver smsc_phy_driver[] = {  {  	.phy_id		= 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */ @@ -159,6 +181,8 @@ static struct phy_driver smsc_phy_driver[] = {  				| SUPPORTED_Asym_Pause),  	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, +	.probe		= smsc_phy_probe, +  	/* basic functions */  	.config_aneg	= genphy_config_aneg,  	.read_status	= genphy_read_status, @@ -180,6 +204,8 @@ static struct phy_driver smsc_phy_driver[] = {  				| SUPPORTED_Asym_Pause),  	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, +	.probe		= smsc_phy_probe, +  	/* basic functions */  	.config_aneg	= genphy_config_aneg,  	.read_status	= genphy_read_status, @@ -201,6 +227,8 @@ static struct phy_driver smsc_phy_driver[] = {  				| SUPPORTED_Asym_Pause),  	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, +	.probe		= smsc_phy_probe, +  	/* basic functions */  	.config_aneg	= genphy_config_aneg,  	.read_status	= lan87xx_read_status, @@ -222,6 +250,8 @@ static struct phy_driver smsc_phy_driver[] = {  				| SUPPORTED_Asym_Pause),  	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, +	.probe		= smsc_phy_probe, +  	/* basic functions */  	.config_aneg	= genphy_config_aneg,  	.read_status	= genphy_read_status, @@ -242,6 +272,8 @@ static struct phy_driver smsc_phy_driver[] = {  				| SUPPORTED_Asym_Pause),  	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, +	.probe		= smsc_phy_probe, +  	/* basic functions */  	.config_aneg	= genphy_config_aneg,  	.read_status	= lan87xx_read_status, @@ -263,6 +295,8 @@ static struct phy_driver smsc_phy_driver[] = {  				| SUPPORTED_Asym_Pause),  	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, +	.probe		= smsc_phy_probe, +  	/* basic functions */  	.config_aneg	= genphy_config_aneg,  	.read_status	= lan87xx_read_status, diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index fc8ad001bc94..d61da9ece3ba 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -443,9 +443,14 @@ static ssize_t ppp_read(struct file *file, char __user *buf,  			 * network traffic (demand mode).  			 */  			struct ppp *ppp = PF_TO_PPP(pf); + +			ppp_recv_lock(ppp);  			if (ppp->n_channels == 0 && -			    (ppp->flags & SC_LOOP_TRAFFIC) == 0) +			    (ppp->flags & SC_LOOP_TRAFFIC) == 0) { +				ppp_recv_unlock(ppp);  				break; +			} +			ppp_recv_unlock(ppp);  		}  		ret = -EAGAIN;  		if (file->f_flags & O_NONBLOCK) @@ -532,9 +537,12 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait)  	else if (pf->kind == INTERFACE) {  		/* see comment in ppp_read */  		struct ppp *ppp = PF_TO_PPP(pf); + +		ppp_recv_lock(ppp);  		if (ppp->n_channels == 0 &&  		    (ppp->flags & SC_LOOP_TRAFFIC) == 0)  			mask |= POLLIN | POLLRDNORM; +		ppp_recv_unlock(ppp);  	}  	return mask; @@ -2808,6 +2816,7 @@ static struct ppp *ppp_create_interface(struct net *net, int unit,  out2:  	mutex_unlock(&pn->all_ppp_mutex); +	rtnl_unlock();  	free_netdev(dev);  out1:  	*retp = ret; diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c index 05005c660d4d..f60f7660b451 100644 --- a/drivers/net/ppp/ppp_mppe.c +++ b/drivers/net/ppp/ppp_mppe.c @@ -42,6 +42,8 @@   *                    deprecated in 2.6   */ +#include <crypto/hash.h> +#include <crypto/skcipher.h>  #include <linux/err.h>  #include <linux/module.h>  #include <linux/kernel.h> @@ -49,7 +51,6 @@  #include <linux/types.h>  #include <linux/slab.h>  #include <linux/string.h> -#include <linux/crypto.h>  #include <linux/mm.h>  #include <linux/ppp_defs.h>  #include <linux/ppp-comp.h> @@ -94,8 +95,8 @@ static inline void sha_pad_init(struct sha_pad *shapad)   * State for an MPPE (de)compressor.   */  struct ppp_mppe_state { -	struct crypto_blkcipher *arc4; -	struct crypto_hash *sha1; +	struct crypto_skcipher *arc4; +	struct crypto_ahash *sha1;  	unsigned char *sha1_digest;  	unsigned char master_key[MPPE_MAX_KEY_LEN];  	unsigned char session_key[MPPE_MAX_KEY_LEN]; @@ -135,7 +136,7 @@ struct ppp_mppe_state {   */  static void get_new_key_from_sha(struct ppp_mppe_state * state)  { -	struct hash_desc desc; +	AHASH_REQUEST_ON_STACK(req, state->sha1);  	struct scatterlist sg[4];  	unsigned int nbytes; @@ -148,10 +149,12 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state)  	nbytes += setup_sg(&sg[3], sha_pad->sha_pad2,  			   sizeof(sha_pad->sha_pad2)); -	desc.tfm = state->sha1; -	desc.flags = 0; +	ahash_request_set_tfm(req, state->sha1); +	ahash_request_set_callback(req, 0, NULL, NULL); +	ahash_request_set_crypt(req, sg, state->sha1_digest, nbytes); -	crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest); +	crypto_ahash_digest(req); +	ahash_request_zero(req);  }  /* @@ -161,20 +164,23 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state)  static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)  {  	struct scatterlist sg_in[1], sg_out[1]; -	struct blkcipher_desc desc = { .tfm = state->arc4 }; +	SKCIPHER_REQUEST_ON_STACK(req, state->arc4); + +	skcipher_request_set_tfm(req, state->arc4); +	skcipher_request_set_callback(req, 0, NULL, NULL);  	get_new_key_from_sha(state);  	if (!initial_key) { -		crypto_blkcipher_setkey(state->arc4, state->sha1_digest, -					state->keylen); +		crypto_skcipher_setkey(state->arc4, state->sha1_digest, +				       state->keylen);  		sg_init_table(sg_in, 1);  		sg_init_table(sg_out, 1);  		setup_sg(sg_in, state->sha1_digest, state->keylen);  		setup_sg(sg_out, state->session_key, state->keylen); -		if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, -					     state->keylen) != 0) { +		skcipher_request_set_crypt(req, sg_in, sg_out, state->keylen, +					   NULL); +		if (crypto_skcipher_encrypt(req))      		    printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n"); -		}  	} else {  		memcpy(state->session_key, state->sha1_digest, state->keylen);  	} @@ -184,7 +190,8 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)  		state->session_key[1] = 0x26;  		state->session_key[2] = 0x9e;  	} -	crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen); +	crypto_skcipher_setkey(state->arc4, state->session_key, state->keylen); +	skcipher_request_zero(req);  }  /* @@ -204,19 +211,19 @@ static void *mppe_alloc(unsigned char *options, int optlen)  		goto out; -	state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); +	state->arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);  	if (IS_ERR(state->arc4)) {  		state->arc4 = NULL;  		goto out_free;  	} -	state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC); +	state->sha1 = crypto_alloc_ahash("sha1", 0, CRYPTO_ALG_ASYNC);  	if (IS_ERR(state->sha1)) {  		state->sha1 = NULL;  		goto out_free;  	} -	digestsize = crypto_hash_digestsize(state->sha1); +	digestsize = crypto_ahash_digestsize(state->sha1);  	if (digestsize < MPPE_MAX_KEY_LEN)  		goto out_free; @@ -237,15 +244,12 @@ static void *mppe_alloc(unsigned char *options, int optlen)  	return (void *)state; -	out_free: -	    if (state->sha1_digest) -		kfree(state->sha1_digest); -	    if (state->sha1) -		crypto_free_hash(state->sha1); -	    if (state->arc4) -		crypto_free_blkcipher(state->arc4); -	    kfree(state); -	out: +out_free: +	kfree(state->sha1_digest); +	crypto_free_ahash(state->sha1); +	crypto_free_skcipher(state->arc4); +	kfree(state); +out:  	return NULL;  } @@ -256,13 +260,10 @@ static void mppe_free(void *arg)  {  	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;  	if (state) { -	    if (state->sha1_digest)  		kfree(state->sha1_digest); -	    if (state->sha1) -		crypto_free_hash(state->sha1); -	    if (state->arc4) -		crypto_free_blkcipher(state->arc4); -	    kfree(state); +		crypto_free_ahash(state->sha1); +		crypto_free_skcipher(state->arc4); +		kfree(state);  	}  } @@ -368,8 +369,9 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,  	      int isize, int osize)  {  	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; -	struct blkcipher_desc desc = { .tfm = state->arc4 }; +	SKCIPHER_REQUEST_ON_STACK(req, state->arc4);  	int proto; +	int err;  	struct scatterlist sg_in[1], sg_out[1];  	/* @@ -426,7 +428,13 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,  	sg_init_table(sg_out, 1);  	setup_sg(sg_in, ibuf, isize);  	setup_sg(sg_out, obuf, osize); -	if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) { + +	skcipher_request_set_tfm(req, state->arc4); +	skcipher_request_set_callback(req, 0, NULL, NULL); +	skcipher_request_set_crypt(req, sg_in, sg_out, isize, NULL); +	err = crypto_skcipher_encrypt(req); +	skcipher_request_zero(req); +	if (err) {  		printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");  		return -1;  	} @@ -475,7 +483,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,  		int osize)  {  	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; -	struct blkcipher_desc desc = { .tfm = state->arc4 }; +	SKCIPHER_REQUEST_ON_STACK(req, state->arc4);  	unsigned ccount;  	int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;  	struct scatterlist sg_in[1], sg_out[1]; @@ -609,9 +617,14 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,  	sg_init_table(sg_out, 1);  	setup_sg(sg_in, ibuf, 1);  	setup_sg(sg_out, obuf, 1); -	if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) { + +	skcipher_request_set_tfm(req, state->arc4); +	skcipher_request_set_callback(req, 0, NULL, NULL); +	skcipher_request_set_crypt(req, sg_in, sg_out, 1, NULL); +	if (crypto_skcipher_decrypt(req)) {  		printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); -		return DECOMP_ERROR; +		osize = DECOMP_ERROR; +		goto out_zap_req;  	}  	/* @@ -629,9 +642,11 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,  	/* And finally, decrypt the rest of the packet. */  	setup_sg(sg_in, ibuf + 1, isize - 1);  	setup_sg(sg_out, obuf + 1, osize - 1); -	if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, isize - 1)) { +	skcipher_request_set_crypt(req, sg_in, sg_out, isize - 1, NULL); +	if (crypto_skcipher_decrypt(req)) {  		printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); -		return DECOMP_ERROR; +		osize = DECOMP_ERROR; +		goto out_zap_req;  	}  	state->stats.unc_bytes += osize; @@ -642,6 +657,8 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,  	/* good packet credit */  	state->sanity_errors >>= 1; +out_zap_req: +	skcipher_request_zero(req);  	return osize;  sanity_error: @@ -714,8 +731,8 @@ static struct compressor ppp_mppe = {  static int __init ppp_mppe_init(void)  {  	int answer; -	if (!(crypto_has_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) && -	      crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC))) +	if (!(crypto_has_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) && +	      crypto_has_ahash("sha1", 0, CRYPTO_ALG_ASYNC)))  		return -ENODEV;  	sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL); diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index f3c63022eb3c..4ddae8118c85 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -395,6 +395,8 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)  		if (!__pppoe_xmit(sk_pppox(relay_po), skb))  			goto abort_put; + +		sock_put(sk_pppox(relay_po));  	} else {  		if (sock_queue_rcv_skb(sk, skb))  			goto abort_kfree; diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 90868ca5e341..ae0905ed4a32 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -129,24 +129,27 @@ static int lookup_chan_dst(u16 call_id, __be32 d_addr)  	return i < MAX_CALLID;  } -static int add_chan(struct pppox_sock *sock) +static int add_chan(struct pppox_sock *sock, +		    struct pptp_addr *sa)  {  	static int call_id;  	spin_lock(&chan_lock); -	if (!sock->proto.pptp.src_addr.call_id)	{ +	if (!sa->call_id)	{  		call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1);  		if (call_id == MAX_CALLID) {  			call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1);  			if (call_id == MAX_CALLID)  				goto out_err;  		} -		sock->proto.pptp.src_addr.call_id = call_id; -	} else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap)) +		sa->call_id = call_id; +	} else if (test_bit(sa->call_id, callid_bitmap)) {  		goto out_err; +	} -	set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); -	rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock); +	sock->proto.pptp.src_addr = *sa; +	set_bit(sa->call_id, callid_bitmap); +	rcu_assign_pointer(callid_sock[sa->call_id], sock);  	spin_unlock(&chan_lock);  	return 0; @@ -416,7 +419,6 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr,  	struct sock *sk = sock->sk;  	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;  	struct pppox_sock *po = pppox_sk(sk); -	struct pptp_opt *opt = &po->proto.pptp;  	int error = 0;  	if (sockaddr_len < sizeof(struct sockaddr_pppox)) @@ -424,10 +426,22 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr,  	lock_sock(sk); -	opt->src_addr = sp->sa_addr.pptp; -	if (add_chan(po)) +	if (sk->sk_state & PPPOX_DEAD) { +		error = -EALREADY; +		goto out; +	} + +	if (sk->sk_state & PPPOX_BOUND) {  		error = -EBUSY; +		goto out; +	} + +	if (add_chan(po, &sp->sa_addr.pptp)) +		error = -EBUSY; +	else +		sk->sk_state |= PPPOX_BOUND; +out:  	release_sock(sk);  	return error;  } @@ -498,7 +512,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,  	}  	opt->dst_addr = sp->sa_addr.pptp; -	sk->sk_state = PPPOX_CONNECTED; +	sk->sk_state |= PPPOX_CONNECTED;   end:  	release_sock(sk); diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 7f83504dfa69..cdde59089f72 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -395,6 +395,10 @@ config USB_NET_RNDIS_HOST  	  The protocol specification is incomplete, and is controlled by  	  (and for) Microsoft; it isn't an "Open" ecosystem or market. +config USB_NET_CDC_SUBSET_ENABLE +	tristate +	depends on USB_NET_CDC_SUBSET +  config USB_NET_CDC_SUBSET  	tristate "Simple USB Network Links (CDC Ethernet subset)"  	depends on USB_USBNET @@ -413,6 +417,7 @@ config USB_NET_CDC_SUBSET  config USB_ALI_M5632  	bool "ALi M5632 based 'USB 2.0 Data Link' cables"  	depends on USB_NET_CDC_SUBSET +	select USB_NET_CDC_SUBSET_ENABLE  	help  	  Choose this option if you're using a host-to-host cable  	  based on this design, which supports USB 2.0 high speed. @@ -420,6 +425,7 @@ config USB_ALI_M5632  config USB_AN2720  	bool "AnchorChips 2720 based cables (Xircom PGUNET, ...)"  	depends on USB_NET_CDC_SUBSET +	select USB_NET_CDC_SUBSET_ENABLE  	help  	  Choose this option if you're using a host-to-host cable  	  based on this design.  Note that AnchorChips is now a @@ -428,6 +434,7 @@ config USB_AN2720  config USB_BELKIN  	bool "eTEK based host-to-host cables (Advance, Belkin, ...)"  	depends on USB_NET_CDC_SUBSET +	select USB_NET_CDC_SUBSET_ENABLE  	default y  	help  	  Choose this option if you're using a host-to-host cable @@ -437,6 +444,7 @@ config USB_BELKIN  config USB_ARMLINUX  	bool "Embedded ARM Linux links (iPaq, ...)"  	depends on USB_NET_CDC_SUBSET +	select USB_NET_CDC_SUBSET_ENABLE  	default y  	help  	  Choose this option to support the "usb-eth" networking driver @@ -454,6 +462,7 @@ config USB_ARMLINUX  config USB_EPSON2888  	bool "Epson 2888 based firmware (DEVELOPMENT)"  	depends on USB_NET_CDC_SUBSET +	select USB_NET_CDC_SUBSET_ENABLE  	help  	  Choose this option to support the usb networking links used  	  by some sample firmware from Epson. @@ -461,6 +470,7 @@ config USB_EPSON2888  config USB_KC2190  	bool "KT Technology KC2190 based cables (InstaNet)"  	depends on USB_NET_CDC_SUBSET +	select USB_NET_CDC_SUBSET_ENABLE  	help  	  Choose this option if you're using a host-to-host cable  	  with one of these chips. diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index b5f04068dbe4..37fb46aee341 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o  obj-$(CONFIG_USB_NET_NET1080)	+= net1080.o  obj-$(CONFIG_USB_NET_PLUSB)	+= plusb.o  obj-$(CONFIG_USB_NET_RNDIS_HOST)	+= rndis_host.o -obj-$(CONFIG_USB_NET_CDC_SUBSET)	+= cdc_subset.o +obj-$(CONFIG_USB_NET_CDC_SUBSET_ENABLE)	+= cdc_subset.o  obj-$(CONFIG_USB_NET_ZAURUS)	+= zaurus.o  obj-$(CONFIG_USB_NET_MCS7830)	+= mcs7830.o  obj-$(CONFIG_USB_USBNET)	+= usbnet.o diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index 224e7d82de6d..cf77f2dffa69 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c @@ -134,7 +134,6 @@ static void ax88172a_remove_mdio(struct usbnet *dev)  	netdev_info(dev->net, "deregistering mdio bus %s\n", priv->mdio->id);  	mdiobus_unregister(priv->mdio); -	kfree(priv->mdio->irq);  	mdiobus_free(priv->mdio);  } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index dc0212c3cc28..86ba30ba35e8 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -837,7 +837,11 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_  	iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber; -	/* reset data interface */ +	/* Reset data interface. Some devices will not reset properly +	 * unless they are configured first.  Toggle the altsetting to +	 * force a reset +	 */ +	usb_set_interface(dev->udev, iface_no, data_altsetting);  	temp = usb_set_interface(dev->udev, iface_no, 0);  	if (temp) {  		dev_dbg(&intf->dev, "set interface failed\n"); @@ -984,8 +988,6 @@ EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting);  static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)  { -	int ret; -  	/* MBIM backwards compatible function? */  	if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)  		return -ENODEV; @@ -994,16 +996,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)  	 * Additionally, generic NCM devices are assumed to accept arbitrarily  	 * placed NDP.  	 */ -	ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0); - -	/* -	 * We should get an event when network connection is "connected" or -	 * "disconnected". Set network connection in "disconnected" state -	 * (carrier is OFF) during attach, so the IP network stack does not -	 * start IPv6 negotiation and more. -	 */ -	usbnet_link_change(dev, 0, 0); -	return ret; +	return cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);  }  static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max) @@ -1586,7 +1579,8 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)  static const struct driver_info cdc_ncm_info = {  	.description = "CDC NCM", -	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET, +	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET +			| FLAG_LINK_INTR,  	.bind = cdc_ncm_bind,  	.unbind = cdc_ncm_unbind,  	.manage_power = usbnet_manage_power, @@ -1599,7 +1593,7 @@ static const struct driver_info cdc_ncm_info = {  static const struct driver_info wwan_info = {  	.description = "Mobile Broadband Network Device",  	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET -			| FLAG_WWAN, +			| FLAG_LINK_INTR | FLAG_WWAN,  	.bind = cdc_ncm_bind,  	.unbind = cdc_ncm_unbind,  	.manage_power = usbnet_manage_power, @@ -1612,7 +1606,7 @@ static const struct driver_info wwan_info = {  static const struct driver_info wwan_noarp_info = {  	.description = "Mobile Broadband Network Device (NO ARP)",  	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET -			| FLAG_WWAN | FLAG_NOARP, +			| FLAG_LINK_INTR | FLAG_WWAN | FLAG_NOARP,  	.bind = cdc_ncm_bind,  	.unbind = cdc_ncm_unbind,  	.manage_power = usbnet_manage_power, diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 2ed53331bfb2..1c299b8a162d 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -36,7 +36,7 @@  #define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"  #define DRIVER_DESC	"LAN78XX USB 3.0 Gigabit Ethernet Devices"  #define DRIVER_NAME	"lan78xx" -#define DRIVER_VERSION	"1.0.1" +#define DRIVER_VERSION	"1.0.2"  #define TX_TIMEOUT_JIFFIES		(5 * HZ)  #define THROTTLE_JIFFIES		(HZ / 8) @@ -462,32 +462,53 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset,  				   u32 length, u8 *data)  {  	u32 val; +	u32 saved;  	int i, ret; +	int retval; -	ret = lan78xx_eeprom_confirm_not_busy(dev); -	if (ret) -		return ret; +	/* depends on chip, some EEPROM pins are muxed with LED function. +	 * disable & restore LED function to access EEPROM. +	 */ +	ret = lan78xx_read_reg(dev, HW_CFG, &val); +	saved = val; +	if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) { +		val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_); +		ret = lan78xx_write_reg(dev, HW_CFG, val); +	} + +	retval = lan78xx_eeprom_confirm_not_busy(dev); +	if (retval) +		return retval;  	for (i = 0; i < length; i++) {  		val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_;  		val |= (offset & E2P_CMD_EPC_ADDR_MASK_);  		ret = lan78xx_write_reg(dev, E2P_CMD, val); -		if (unlikely(ret < 0)) -			return -EIO; +		if (unlikely(ret < 0)) { +			retval = -EIO; +			goto exit; +		} -		ret = lan78xx_wait_eeprom(dev); -		if (ret < 0) -			return ret; +		retval = lan78xx_wait_eeprom(dev); +		if (retval < 0) +			goto exit;  		ret = lan78xx_read_reg(dev, E2P_DATA, &val); -		if (unlikely(ret < 0)) -			return -EIO; +		if (unlikely(ret < 0)) { +			retval = -EIO; +			goto exit; +		}  		data[i] = val & 0xFF;  		offset++;  	} -	return 0; +	retval = 0; +exit: +	if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) +		ret = lan78xx_write_reg(dev, HW_CFG, saved); + +	return retval;  }  static int lan78xx_read_eeprom(struct lan78xx_net *dev, u32 offset, @@ -509,44 +530,67 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset,  				    u32 length, u8 *data)  {  	u32 val; +	u32 saved;  	int i, ret; +	int retval; -	ret = lan78xx_eeprom_confirm_not_busy(dev); -	if (ret) -		return ret; +	/* depends on chip, some EEPROM pins are muxed with LED function. +	 * disable & restore LED function to access EEPROM. +	 */ +	ret = lan78xx_read_reg(dev, HW_CFG, &val); +	saved = val; +	if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) { +		val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_); +		ret = lan78xx_write_reg(dev, HW_CFG, val); +	} + +	retval = lan78xx_eeprom_confirm_not_busy(dev); +	if (retval) +		goto exit;  	/* Issue write/erase enable command */  	val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_;  	ret = lan78xx_write_reg(dev, E2P_CMD, val); -	if (unlikely(ret < 0)) -		return -EIO; +	if (unlikely(ret < 0)) { +		retval = -EIO; +		goto exit; +	} -	ret = lan78xx_wait_eeprom(dev); -	if (ret < 0) -		return ret; +	retval = lan78xx_wait_eeprom(dev); +	if (retval < 0) +		goto exit;  	for (i = 0; i < length; i++) {  		/* Fill data register */  		val = data[i];  		ret = lan78xx_write_reg(dev, E2P_DATA, val); -		if (ret < 0) -			return ret; +		if (ret < 0) { +			retval = -EIO; +			goto exit; +		}  		/* Send "write" command */  		val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_;  		val |= (offset & E2P_CMD_EPC_ADDR_MASK_);  		ret = lan78xx_write_reg(dev, E2P_CMD, val); -		if (ret < 0) -			return ret; +		if (ret < 0) { +			retval = -EIO; +			goto exit; +		} -		ret = lan78xx_wait_eeprom(dev); -		if (ret < 0) -			return ret; +		retval = lan78xx_wait_eeprom(dev); +		if (retval < 0) +			goto exit;  		offset++;  	} -	return 0; +	retval = 0; +exit: +	if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) +		ret = lan78xx_write_reg(dev, HW_CFG, saved); + +	return retval;  }  static int lan78xx_read_raw_otp(struct lan78xx_net *dev, u32 offset, @@ -904,7 +948,6 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)  	if (!phydev->link && dev->link_on) {  		dev->link_on = false; -		netif_carrier_off(dev->net);  		/* reset MAC */  		ret = lan78xx_read_reg(dev, MAC_CR, &buf); @@ -914,6 +957,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)  		ret = lan78xx_write_reg(dev, MAC_CR, buf);  		if (unlikely(ret < 0))  			return -EIO; + +		phy_mac_interrupt(phydev, 0);  	} else if (phydev->link && !dev->link_on) {  		dev->link_on = true; @@ -953,7 +998,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)  			  ethtool_cmd_speed(&ecmd), ecmd.duplex, ladv, radv);  		ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv); -		netif_carrier_on(dev->net); +		phy_mac_interrupt(phydev, 1);  	}  	return ret; @@ -1495,7 +1540,6 @@ done:  static int lan78xx_mdio_init(struct lan78xx_net *dev)  {  	int ret; -	int i;  	dev->mdiobus = mdiobus_alloc();  	if (!dev->mdiobus) { @@ -1511,10 +1555,6 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)  	snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",  		 dev->udev->bus->busnum, dev->udev->devnum); -	/* handle our own interrupt */ -	for (i = 0; i < PHY_MAX_ADDR; i++) -		dev->mdiobus->irq[i] = PHY_IGNORE_INTERRUPT; -  	switch (dev->devid & ID_REV_CHIP_ID_MASK_) {  	case 0x78000000:  	case 0x78500000: @@ -1558,6 +1598,16 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)  		return -EIO;  	} +	/* Enable PHY interrupts. +	 * We handle our own interrupt +	 */ +	ret = phy_read(phydev, LAN88XX_INT_STS); +	ret = phy_write(phydev, LAN88XX_INT_MASK, +			LAN88XX_INT_MASK_MDINTPIN_EN_ | +			LAN88XX_INT_MASK_LINK_CHANGE_); + +	phydev->irq = PHY_IGNORE_INTERRUPT; +  	ret = phy_connect_direct(dev->net, phydev,  				 lan78xx_link_status_change,  				 PHY_INTERFACE_MODE_GMII); @@ -1580,14 +1630,6 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)  			      SUPPORTED_Pause | SUPPORTED_Asym_Pause);  	genphy_config_aneg(phydev); -	/* Workaround to enable PHY interrupt. -	 * phy_start_interrupts() is API for requesting and enabling -	 * PHY interrupt. However, USB-to-Ethernet device can't use -	 * request_irq() called in phy_start_interrupts(). -	 * Set PHY to PHY_HALTED and call phy_start() -	 * to make a call to phy_enable_interrupts() -	 */ -	phy_stop(phydev);  	phy_start(phydev);  	netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); @@ -2221,7 +2263,9 @@ netdev_tx_t lan78xx_start_xmit(struct sk_buff *skb, struct net_device *net)  	if (skb2) {  		skb_queue_tail(&dev->txq_pend, skb2); -		if (skb_queue_len(&dev->txq_pend) > 10) +		/* throttle TX patch at slower than SUPER SPEED USB */ +		if ((dev->udev->speed < USB_SPEED_SUPER) && +		    (skb_queue_len(&dev->txq_pend) > 10))  			netif_stop_queue(net);  	} else {  		netif_dbg(dev, tx_err, dev->net, diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 23e9880791fc..a3a4ccf7cf52 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -637,6 +637,7 @@ static const struct usb_device_id products[] = {  	/* 3. Combined interface devices matching on interface number */  	{QMI_FIXED_INTF(0x0408, 0xea42, 4)},	/* Yota / Megafon M100-1 */ +	{QMI_FIXED_INTF(0x05c6, 0x6001, 3)},	/* 4G LTE usb-modem U901 */  	{QMI_FIXED_INTF(0x05c6, 0x7000, 0)},  	{QMI_FIXED_INTF(0x05c6, 0x7001, 1)},  	{QMI_FIXED_INTF(0x05c6, 0x7002, 1)}, @@ -860,8 +861,10 @@ static const struct usb_device_id products[] = {  	{QMI_FIXED_INTF(0x1199, 0x9056, 8)},	/* Sierra Wireless Modem */  	{QMI_FIXED_INTF(0x1199, 0x9057, 8)},  	{QMI_FIXED_INTF(0x1199, 0x9061, 8)},	/* Sierra Wireless Modem */ -	{QMI_FIXED_INTF(0x1199, 0x9071, 8)},	/* Sierra Wireless MC74xx/EM74xx */ -	{QMI_FIXED_INTF(0x1199, 0x9071, 10)},	/* Sierra Wireless MC74xx/EM74xx */ +	{QMI_FIXED_INTF(0x1199, 0x9071, 8)},	/* Sierra Wireless MC74xx */ +	{QMI_FIXED_INTF(0x1199, 0x9071, 10)},	/* Sierra Wireless MC74xx */ +	{QMI_FIXED_INTF(0x1199, 0x9079, 8)},	/* Sierra Wireless EM74xx */ +	{QMI_FIXED_INTF(0x1199, 0x9079, 10)},	/* Sierra Wireless EM74xx */  	{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},	/* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */  	{QMI_FIXED_INTF(0x1bbb, 0x0203, 2)},	/* Alcatel L800MA */  	{QMI_FIXED_INTF(0x2357, 0x0201, 4)},	/* TP-LINK HSUPA Modem MA180 */ @@ -884,6 +887,7 @@ static const struct usb_device_id products[] = {  	{QMI_FIXED_INTF(0x413c, 0x81a8, 8)},	/* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */  	{QMI_FIXED_INTF(0x413c, 0x81a9, 8)},	/* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */  	{QMI_FIXED_INTF(0x413c, 0x81b1, 8)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */ +	{QMI_FIXED_INTF(0x413c, 0x81b3, 8)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */  	{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},	/* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */  	{QMI_FIXED_INTF(0x22de, 0x9061, 3)},	/* WeTelecom WPD-600N */  	{QMI_FIXED_INTF(0x1e0e, 0x9001, 5)},	/* SIMCom 7230E */ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 0b0ba7ef14e4..10798128c03f 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1769,6 +1769,13 @@ out3:  	if (info->unbind)  		info->unbind (dev, udev);  out1: +	/* subdrivers must undo all they did in bind() if they +	 * fail it, but we may fail later and a deferred kevent +	 * may trigger an error resubmitting itself and, worse, +	 * schedule a timer. So we kill it all just in case. +	 */ +	cancel_work_sync(&dev->kevent); +	del_timer_sync(&dev->delay);  	free_netdev(net);  out:  	return status; diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index 221a53025fd0..72ba8ae7f09a 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -377,7 +377,7 @@ union Vmxnet3_GenericDesc {  #define VMXNET3_TX_RING_MAX_SIZE   4096  #define VMXNET3_TC_RING_MAX_SIZE   4096  #define VMXNET3_RX_RING_MAX_SIZE   4096 -#define VMXNET3_RX_RING2_MAX_SIZE  2048 +#define VMXNET3_RX_RING2_MAX_SIZE  4096  #define VMXNET3_RC_RING_MAX_SIZE   8192  /* a list of reasons for queue stop */ diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 0cbf520cea77..fc895d0e85d9 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -814,7 +814,7 @@ vmxnet3_tq_init_all(struct vmxnet3_adapter *adapter)  /* - *    parse and copy relevant protocol headers: + *    parse relevant protocol headers:   *      For a tso pkt, relevant headers are L2/3/4 including options   *      For a pkt requesting csum offloading, they are L2/3 and may include L4   *      if it's a TCP/UDP pkt @@ -827,15 +827,14 @@ vmxnet3_tq_init_all(struct vmxnet3_adapter *adapter)   * Other effects:   *    1. related *ctx fields are updated.   *    2. ctx->copy_size is # of bytes copied - *    3. the portion copied is guaranteed to be in the linear part + *    3. the portion to be copied is guaranteed to be in the linear part   *   */  static int -vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, -			   struct vmxnet3_tx_ctx *ctx, -			   struct vmxnet3_adapter *adapter) +vmxnet3_parse_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, +		  struct vmxnet3_tx_ctx *ctx, +		  struct vmxnet3_adapter *adapter)  { -	struct Vmxnet3_TxDataDesc *tdd;  	u8 protocol = 0;  	if (ctx->mss) {	/* TSO */ @@ -892,16 +891,34 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,  		return 0;  	} +	return 1; +err: +	return -1; +} + +/* + *    copy relevant protocol headers to the transmit ring: + *      For a tso pkt, relevant headers are L2/3/4 including options + *      For a pkt requesting csum offloading, they are L2/3 and may include L4 + *      if it's a TCP/UDP pkt + * + * + *    Note that this requires that vmxnet3_parse_hdr be called first to set the + *      appropriate bits in ctx first + */ +static void +vmxnet3_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, +		 struct vmxnet3_tx_ctx *ctx, +		 struct vmxnet3_adapter *adapter) +{ +	struct Vmxnet3_TxDataDesc *tdd; +  	tdd = tq->data_ring.base + tq->tx_ring.next2fill;  	memcpy(tdd->data, skb->data, ctx->copy_size);  	netdev_dbg(adapter->netdev,  		"copy %u bytes to dataRing[%u]\n",  		ctx->copy_size, tq->tx_ring.next2fill); -	return 1; - -err: -	return -1;  } @@ -998,22 +1015,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,  		}  	} -	spin_lock_irqsave(&tq->tx_lock, flags); - -	if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) { -		tq->stats.tx_ring_full++; -		netdev_dbg(adapter->netdev, -			"tx queue stopped on %s, next2comp %u" -			" next2fill %u\n", adapter->netdev->name, -			tq->tx_ring.next2comp, tq->tx_ring.next2fill); - -		vmxnet3_tq_stop(tq, adapter); -		spin_unlock_irqrestore(&tq->tx_lock, flags); -		return NETDEV_TX_BUSY; -	} - - -	ret = vmxnet3_parse_and_copy_hdr(skb, tq, &ctx, adapter); +	ret = vmxnet3_parse_hdr(skb, tq, &ctx, adapter);  	if (ret >= 0) {  		BUG_ON(ret <= 0 && ctx.copy_size != 0);  		/* hdrs parsed, check against other limits */ @@ -1033,9 +1035,26 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,  		}  	} else {  		tq->stats.drop_hdr_inspect_err++; -		goto unlock_drop_pkt; +		goto drop_pkt;  	} +	spin_lock_irqsave(&tq->tx_lock, flags); + +	if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) { +		tq->stats.tx_ring_full++; +		netdev_dbg(adapter->netdev, +			"tx queue stopped on %s, next2comp %u" +			" next2fill %u\n", adapter->netdev->name, +			tq->tx_ring.next2comp, tq->tx_ring.next2fill); + +		vmxnet3_tq_stop(tq, adapter); +		spin_unlock_irqrestore(&tq->tx_lock, flags); +		return NETDEV_TX_BUSY; +	} + + +	vmxnet3_copy_hdr(skb, tq, &ctx, adapter); +  	/* fill tx descs related to addr & len */  	if (vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter))  		goto unlock_drop_pkt; diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index bdb8a6c0f8aa..729c344e6774 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,10 @@  /*   * Version numbers   */ -#define VMXNET3_DRIVER_VERSION_STRING   "1.4.5.0-k" +#define VMXNET3_DRIVER_VERSION_STRING   "1.4.6.0-k"  /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM      0x01040500 +#define VMXNET3_DRIVER_VERSION_NUM      0x01040600  #if defined(CONFIG_PCI_MSI)  	/* RSS only makes sense if MSI-X is supported. */ diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 66addb7a7911..bdcf617a9d52 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -104,20 +104,23 @@ static struct dst_ops vrf_dst_ops = {  #if IS_ENABLED(CONFIG_IPV6)  static bool check_ipv6_frame(const struct sk_buff *skb)  { -	const struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->data; -	size_t hlen = sizeof(*ipv6h); +	const struct ipv6hdr *ipv6h; +	struct ipv6hdr _ipv6h;  	bool rc = true; -	if (skb->len < hlen) +	ipv6h = skb_header_pointer(skb, 0, sizeof(_ipv6h), &_ipv6h); +	if (!ipv6h)  		goto out;  	if (ipv6h->nexthdr == NEXTHDR_ICMP) {  		const struct icmp6hdr *icmph; +		struct icmp6hdr _icmph; -		if (skb->len < hlen + sizeof(*icmph)) +		icmph = skb_header_pointer(skb, sizeof(_ipv6h), +					   sizeof(_icmph), &_icmph); +		if (!icmph)  			goto out; -		icmph = (struct icmp6hdr *)(skb->data + sizeof(*ipv6h));  		switch (icmph->icmp6_type) {  		case NDISC_ROUTER_SOLICITATION:  		case NDISC_ROUTER_ADVERTISEMENT: diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 2d88c799d2ac..1c32bd104797 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -73,7 +73,7 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");  static int vxlan_net_id;  static struct rtnl_link_ops vxlan_link_ops; -static const u8 all_zeros_mac[ETH_ALEN]; +static const u8 all_zeros_mac[ETH_ALEN + 2];  static int vxlan_sock_add(struct vxlan_dev *vxlan); @@ -931,8 +931,10 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,  						     cb->nlh->nlmsg_seq,  						     RTM_NEWNEIGH,  						     NLM_F_MULTI, rd); -				if (err < 0) +				if (err < 0) { +					cb->args[1] = err;  					goto out; +				}  skip:  				++idx;  			} @@ -1306,8 +1308,10 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)  		gbp = (struct vxlanhdr_gbp *)vxh;  		md->gbp = ntohs(gbp->policy_id); -		if (tun_dst) +		if (tun_dst) {  			tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT; +			tun_dst->u.tun_info.options_len = sizeof(*md); +		}  		if (gbp->dont_learn)  			md->gbp |= VXLAN_GBP_DONT_LEARN; @@ -1985,11 +1989,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  				     vxlan->cfg.port_max, true);  	if (info) { -		if (info->key.tun_flags & TUNNEL_CSUM) -			flags |= VXLAN_F_UDP_CSUM; -		else -			flags &= ~VXLAN_F_UDP_CSUM; -  		ttl = info->key.ttl;  		tos = info->key.tos; @@ -2004,8 +2003,15 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  			goto drop;  		sk = vxlan->vn4_sock->sock->sk; -		if (info && (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)) -			df = htons(IP_DF); +		if (info) { +			if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) +				df = htons(IP_DF); + +			if (info->key.tun_flags & TUNNEL_CSUM) +				flags |= VXLAN_F_UDP_CSUM; +			else +				flags &= ~VXLAN_F_UDP_CSUM; +		}  		memset(&fl4, 0, sizeof(fl4));  		fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0; @@ -2101,6 +2107,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  			return;  		} +		if (info) { +			if (info->key.tun_flags & TUNNEL_CSUM) +				flags &= ~VXLAN_F_UDP_ZERO_CSUM6_TX; +			else +				flags |= VXLAN_F_UDP_ZERO_CSUM6_TX; +		} +  		ttl = ttl ? : ip6_dst_hoplimit(ndst);  		err = vxlan6_xmit_skb(ndst, sk, skb, dev, &saddr, &dst->sin6.sin6_addr,  				      0, ttl, src_port, dst_port, htonl(vni << 8), md, @@ -2162,9 +2175,11 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)  #endif  	} -	if (vxlan->flags & VXLAN_F_COLLECT_METADATA && -	    info && info->mode & IP_TUNNEL_INFO_TX) { -		vxlan_xmit_one(skb, dev, NULL, false); +	if (vxlan->flags & VXLAN_F_COLLECT_METADATA) { +		if (info && info->mode & IP_TUNNEL_INFO_TX) +			vxlan_xmit_one(skb, dev, NULL, false); +		else +			kfree_skb(skb);  		return NETDEV_TX_OK;  	} @@ -2358,29 +2373,43 @@ static void vxlan_set_multicast_list(struct net_device *dev)  {  } -static int vxlan_change_mtu(struct net_device *dev, int new_mtu) +static int __vxlan_change_mtu(struct net_device *dev, +			      struct net_device *lowerdev, +			      struct vxlan_rdst *dst, int new_mtu, bool strict)  { -	struct vxlan_dev *vxlan = netdev_priv(dev); -	struct vxlan_rdst *dst = &vxlan->default_dst; -	struct net_device *lowerdev; -	int max_mtu; +	int max_mtu = IP_MAX_MTU; -	lowerdev = __dev_get_by_index(vxlan->net, dst->remote_ifindex); -	if (lowerdev == NULL) -		return eth_change_mtu(dev, new_mtu); +	if (lowerdev) +		max_mtu = lowerdev->mtu;  	if (dst->remote_ip.sa.sa_family == AF_INET6) -		max_mtu = lowerdev->mtu - VXLAN6_HEADROOM; +		max_mtu -= VXLAN6_HEADROOM;  	else -		max_mtu = lowerdev->mtu - VXLAN_HEADROOM; +		max_mtu -= VXLAN_HEADROOM; -	if (new_mtu < 68 || new_mtu > max_mtu) +	if (new_mtu < 68)  		return -EINVAL; +	if (new_mtu > max_mtu) { +		if (strict) +			return -EINVAL; + +		new_mtu = max_mtu; +	} +  	dev->mtu = new_mtu;  	return 0;  } +static int vxlan_change_mtu(struct net_device *dev, int new_mtu) +{ +	struct vxlan_dev *vxlan = netdev_priv(dev); +	struct vxlan_rdst *dst = &vxlan->default_dst; +	struct net_device *lowerdev = __dev_get_by_index(vxlan->net, +							 dst->remote_ifindex); +	return __vxlan_change_mtu(dev, lowerdev, dst, new_mtu, true); +} +  static int egress_ipv4_tun_info(struct net_device *dev, struct sk_buff *skb,  				struct ip_tunnel_info *info,  				__be16 sport, __be16 dport) @@ -2514,6 +2543,7 @@ static void vxlan_setup(struct net_device *dev)  	dev->hw_features |= NETIF_F_GSO_SOFTWARE;  	dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;  	netif_keep_dst(dev); +	dev->priv_flags &= ~IFF_TX_SKB_SHARING;  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;  	INIT_LIST_HEAD(&vxlan->next); @@ -2756,6 +2786,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,  	int err;  	bool use_ipv6 = false;  	__be16 default_port = vxlan->cfg.dst_port; +	struct net_device *lowerdev = NULL;  	vxlan->net = src_net; @@ -2776,9 +2807,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,  	}  	if (conf->remote_ifindex) { -		struct net_device *lowerdev -			 = __dev_get_by_index(src_net, conf->remote_ifindex); - +		lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);  		dst->remote_ifindex = conf->remote_ifindex;  		if (!lowerdev) { @@ -2802,6 +2831,12 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,  		needed_headroom = lowerdev->hard_header_len;  	} +	if (conf->mtu) { +		err = __vxlan_change_mtu(dev, lowerdev, dst, conf->mtu, false); +		if (err) +			return err; +	} +  	if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)  		needed_headroom += VXLAN6_HEADROOM;  	else diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 7a72407208b1..629225980463 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -1626,7 +1626,7 @@ try:  		if (state & Xpr) {  			void __iomem *scc_addr;  			unsigned long ring; -			int i; +			unsigned int i;  			/*  			 * - the busy condition happens (sometimes); diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index a7afdeee698c..73fb4232f9f2 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -150,18 +150,18 @@ int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)  		return -EIO;  	} -	if (magic == AR5416_EEPROM_MAGIC) { -		*swap_needed = false; -	} else if (swab16(magic) == AR5416_EEPROM_MAGIC) { +	*swap_needed = false; +	if (swab16(magic) == AR5416_EEPROM_MAGIC) {  		if (ah->ah_flags & AH_NO_EEP_SWAP) {  			ath_info(common,  				 "Ignoring endianness difference in EEPROM magic bytes.\n"); - -			*swap_needed = false;  		} else {  			*swap_needed = true;  		} -	} else { +	} else if (magic != AR5416_EEPROM_MAGIC) { +		if (ath9k_hw_use_flash(ah)) +			return 0; +  		ath_err(common,  			"Invalid EEPROM Magic (0x%04x).\n", magic);  		return -EINVAL; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 53637399bb99..b98db8a0a069 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -879,11 +879,24 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)  	return 0;  } -static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) +void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)  { +	struct sdio_func *func; +	struct mmc_host *host; +	uint max_blocks;  	uint nents;  	int err; +	func = sdiodev->func[2]; +	host = func->card->host; +	sdiodev->sg_support = host->max_segs > 1; +	max_blocks = min_t(uint, host->max_blk_count, 511u); +	sdiodev->max_request_size = min_t(uint, host->max_req_size, +					  max_blocks * func->cur_blksize); +	sdiodev->max_segment_count = min_t(uint, host->max_segs, +					   SG_MAX_SINGLE_ALLOC); +	sdiodev->max_segment_size = host->max_seg_size; +  	if (!sdiodev->sg_support)  		return; @@ -1021,9 +1034,6 @@ static void brcmf_sdiod_host_fixup(struct mmc_host *host)  static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)  { -	struct sdio_func *func; -	struct mmc_host *host; -	uint max_blocks;  	int ret = 0;  	sdiodev->num_funcs = 2; @@ -1054,26 +1064,6 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)  		goto out;  	} -	/* -	 * determine host related variables after brcmf_sdiod_probe() -	 * as func->cur_blksize is properly set and F2 init has been -	 * completed successfully. -	 */ -	func = sdiodev->func[2]; -	host = func->card->host; -	sdiodev->sg_support = host->max_segs > 1; -	max_blocks = min_t(uint, host->max_blk_count, 511u); -	sdiodev->max_request_size = min_t(uint, host->max_req_size, -					  max_blocks * func->cur_blksize); -	sdiodev->max_segment_count = min_t(uint, host->max_segs, -					   SG_MAX_SINGLE_ALLOC); -	sdiodev->max_segment_size = host->max_seg_size; - -	/* allocate scatter-gather table. sg support -	 * will be disabled upon allocation failure. -	 */ -	brcmf_sdiod_sgtable_alloc(sdiodev); -  	ret = brcmf_sdiod_freezer_attach(sdiodev);  	if (ret)  		goto out; @@ -1084,7 +1074,7 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)  		ret = -ENODEV;  		goto out;  	} -	brcmf_sdiod_host_fixup(host); +	brcmf_sdiod_host_fixup(sdiodev->func[2]->card->host);  out:  	if (ret)  		brcmf_sdiod_remove(sdiodev); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 4265b50faa98..cfee477a6eb1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -17,6 +17,7 @@  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/netdevice.h> +#include <linux/module.h>  #include <brcmu_wifi.h>  #include <brcmu_utils.h>  #include "core.h" diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index dd6614332836..a14d9d9da094 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -4114,6 +4114,11 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)  		goto fail;  	} +	/* allocate scatter-gather table. sg support +	 * will be disabled upon allocation failure. +	 */ +	brcmf_sdiod_sgtable_alloc(bus->sdiodev); +  	/* Query the F2 block size, set roundup accordingly */  	bus->blocksize = bus->sdiodev->func[2]->cur_blksize;  	bus->roundup = min(max_roundup, bus->blocksize); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index 5ec7a6d87672..23f223150cef 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -342,6 +342,7 @@ int brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,  /* Issue an abort to the specified function */  int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn); +void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev);  void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,  			      enum brcmf_sdiod_state state);  #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index 866067789330..7438fbeef744 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -53,7 +53,6 @@ config IWLWIFI_LEDS  config IWLDVM  	tristate "Intel Wireless WiFi DVM Firmware support" -	depends on m  	help  	  This is the driver that supports the DVM firmware. The list  	  of the devices that use this firmware is available here: diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c index e60cf141ed79..fa41a5e1c890 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c @@ -74,16 +74,19 @@  #define IWL7260_UCODE_API_MAX	17  #define IWL7265_UCODE_API_MAX	17  #define IWL7265D_UCODE_API_MAX	20 +#define IWL3168_UCODE_API_MAX	20  /* Oldest version we won't warn about */  #define IWL7260_UCODE_API_OK	13  #define IWL7265_UCODE_API_OK	13  #define IWL7265D_UCODE_API_OK	13 +#define IWL3168_UCODE_API_OK	20  /* Lowest firmware API version supported */  #define IWL7260_UCODE_API_MIN	13  #define IWL7265_UCODE_API_MIN	13  #define IWL7265D_UCODE_API_MIN	13 +#define IWL3168_UCODE_API_MIN	20  /* NVM versions */  #define IWL7260_NVM_VERSION		0x0a1d @@ -92,6 +95,8 @@  #define IWL3160_TX_POWER_VERSION	0xffff /* meaningless */  #define IWL3165_NVM_VERSION		0x709  #define IWL3165_TX_POWER_VERSION	0xffff /* meaningless */ +#define IWL3168_NVM_VERSION		0xd01 +#define IWL3168_TX_POWER_VERSION	0xffff /* meaningless */  #define IWL7265_NVM_VERSION		0x0a1d  #define IWL7265_TX_POWER_VERSION	0xffff /* meaningless */  #define IWL7265D_NVM_VERSION		0x0c11 @@ -109,6 +114,9 @@  #define IWL3160_FW_PRE "iwlwifi-3160-"  #define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode" +#define IWL3168_FW_PRE "iwlwifi-3168-" +#define IWL3168_MODULE_FIRMWARE(api) IWL3168_FW_PRE __stringify(api) ".ucode" +  #define IWL7265_FW_PRE "iwlwifi-7265-"  #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" @@ -180,6 +188,12 @@ static const struct iwl_ht_params iwl7000_ht_params = {  	.ucode_api_ok = IWL7265_UCODE_API_OK,			\  	.ucode_api_min = IWL7265_UCODE_API_MIN +#define IWL_DEVICE_3008						\ +	IWL_DEVICE_7000_COMMON,					\ +	.ucode_api_max = IWL3168_UCODE_API_MAX,			\ +	.ucode_api_ok = IWL3168_UCODE_API_OK,			\ +	.ucode_api_min = IWL3168_UCODE_API_MIN +  #define IWL_DEVICE_7005D					\  	IWL_DEVICE_7000_COMMON,					\  	.ucode_api_max = IWL7265D_UCODE_API_MAX,		\ @@ -299,11 +313,11 @@ const struct iwl_cfg iwl3165_2ac_cfg = {  const struct iwl_cfg iwl3168_2ac_cfg = {  	.name = "Intel(R) Dual Band Wireless AC 3168", -	.fw_name_pre = IWL7265D_FW_PRE, -	IWL_DEVICE_7000, +	.fw_name_pre = IWL3168_FW_PRE, +	IWL_DEVICE_3008,  	.ht_params = &iwl7000_ht_params, -	.nvm_ver = IWL3165_NVM_VERSION, -	.nvm_calib_ver = IWL3165_TX_POWER_VERSION, +	.nvm_ver = IWL3168_NVM_VERSION, +	.nvm_calib_ver = IWL3168_TX_POWER_VERSION,  	.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,  	.dccm_len = IWL7265_DCCM_LEN,  }; @@ -376,5 +390,6 @@ const struct iwl_cfg iwl7265d_n_cfg = {  MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));  MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); +MODULE_FIRMWARE(IWL3168_MODULE_FIRMWARE(IWL3168_UCODE_API_OK));  MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_OK));  MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_OK)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index c84a0299d43e..bce9b3420a13 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -7,6 +7,7 @@   *   * Copyright(c) 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -70,12 +71,15 @@  /* Highest firmware API version supported */  #define IWL8000_UCODE_API_MAX	20 +#define IWL8265_UCODE_API_MAX	20  /* Oldest version we won't warn about */  #define IWL8000_UCODE_API_OK	13 +#define IWL8265_UCODE_API_OK	20  /* Lowest firmware API version supported */  #define IWL8000_UCODE_API_MIN	13 +#define IWL8265_UCODE_API_MIN	20  /* NVM versions */  #define IWL8000_NVM_VERSION		0x0a1d @@ -93,6 +97,10 @@  #define IWL8000_MODULE_FIRMWARE(api) \  	IWL8000_FW_PRE "-" __stringify(api) ".ucode" +#define IWL8265_FW_PRE "iwlwifi-8265-" +#define IWL8265_MODULE_FIRMWARE(api) \ +	IWL8265_FW_PRE __stringify(api) ".ucode" +  #define NVM_HW_SECTION_NUM_FAMILY_8000		10  #define DEFAULT_NVM_FILE_FAMILY_8000B		"nvmData-8000B"  #define DEFAULT_NVM_FILE_FAMILY_8000C		"nvmData-8000C" @@ -144,10 +152,7 @@ static const struct iwl_tt_params iwl8000_tt_params = {  	.support_tx_backoff = true,  }; -#define IWL_DEVICE_8000							\ -	.ucode_api_max = IWL8000_UCODE_API_MAX,				\ -	.ucode_api_ok = IWL8000_UCODE_API_OK,				\ -	.ucode_api_min = IWL8000_UCODE_API_MIN,				\ +#define IWL_DEVICE_8000_COMMON						\  	.device_family = IWL_DEVICE_FAMILY_8000,			\  	.max_inst_size = IWL60_RTC_INST_SIZE,				\  	.max_data_size = IWL60_RTC_DATA_SIZE,				\ @@ -167,10 +172,28 @@ static const struct iwl_tt_params iwl8000_tt_params = {  	.thermal_params = &iwl8000_tt_params,				\  	.apmg_not_supported = true +#define IWL_DEVICE_8000							\ +	IWL_DEVICE_8000_COMMON,						\ +	.ucode_api_max = IWL8000_UCODE_API_MAX,				\ +	.ucode_api_ok = IWL8000_UCODE_API_OK,				\ +	.ucode_api_min = IWL8000_UCODE_API_MIN				\ + +#define IWL_DEVICE_8260							\ +	IWL_DEVICE_8000_COMMON,						\ +	.ucode_api_max = IWL8000_UCODE_API_MAX,				\ +	.ucode_api_ok = IWL8000_UCODE_API_OK,				\ +	.ucode_api_min = IWL8000_UCODE_API_MIN				\ + +#define IWL_DEVICE_8265							\ +	IWL_DEVICE_8000_COMMON,						\ +	.ucode_api_max = IWL8265_UCODE_API_MAX,				\ +	.ucode_api_ok = IWL8265_UCODE_API_OK,				\ +	.ucode_api_min = IWL8265_UCODE_API_MIN				\ +  const struct iwl_cfg iwl8260_2n_cfg = {  	.name = "Intel(R) Dual Band Wireless N 8260",  	.fw_name_pre = IWL8000_FW_PRE, -	IWL_DEVICE_8000, +	IWL_DEVICE_8260,  	.ht_params = &iwl8000_ht_params,  	.nvm_ver = IWL8000_NVM_VERSION,  	.nvm_calib_ver = IWL8000_TX_POWER_VERSION, @@ -179,7 +202,7 @@ const struct iwl_cfg iwl8260_2n_cfg = {  const struct iwl_cfg iwl8260_2ac_cfg = {  	.name = "Intel(R) Dual Band Wireless AC 8260",  	.fw_name_pre = IWL8000_FW_PRE, -	IWL_DEVICE_8000, +	IWL_DEVICE_8260,  	.ht_params = &iwl8000_ht_params,  	.nvm_ver = IWL8000_NVM_VERSION,  	.nvm_calib_ver = IWL8000_TX_POWER_VERSION, @@ -188,8 +211,8 @@ const struct iwl_cfg iwl8260_2ac_cfg = {  const struct iwl_cfg iwl8265_2ac_cfg = {  	.name = "Intel(R) Dual Band Wireless AC 8265", -	.fw_name_pre = IWL8000_FW_PRE, -	IWL_DEVICE_8000, +	.fw_name_pre = IWL8265_FW_PRE, +	IWL_DEVICE_8265,  	.ht_params = &iwl8000_ht_params,  	.nvm_ver = IWL8000_NVM_VERSION,  	.nvm_calib_ver = IWL8000_TX_POWER_VERSION, @@ -209,7 +232,7 @@ const struct iwl_cfg iwl4165_2ac_cfg = {  const struct iwl_cfg iwl8260_2ac_sdio_cfg = {  	.name = "Intel(R) Dual Band Wireless-AC 8260",  	.fw_name_pre = IWL8000_FW_PRE, -	IWL_DEVICE_8000, +	IWL_DEVICE_8260,  	.ht_params = &iwl8000_ht_params,  	.nvm_ver = IWL8000_NVM_VERSION,  	.nvm_calib_ver = IWL8000_TX_POWER_VERSION, @@ -236,3 +259,4 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {  };  MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); +MODULE_FIRMWARE(IWL8265_MODULE_FIRMWARE(IWL8265_UCODE_API_OK)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 7acb49075683..ab4c2a0470b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -243,8 +243,10 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)  	if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {  		char rev_step = 'A' + CSR_HW_REV_STEP(drv->trans->hw_rev); -		snprintf(drv->firmware_name, sizeof(drv->firmware_name), -			 "%s%c-%s.ucode", name_pre, rev_step, tag); +		if (rev_step != 'A') +			snprintf(drv->firmware_name, +				 sizeof(drv->firmware_name), "%s%c-%s.ucode", +				 name_pre, rev_step, tag);  	}  	IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 0036d18334af..ba3f0bbddde8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -510,6 +510,9 @@ struct iwl_mvm_tx_resp {   * @scd_ssn: the index of the last contiguously sent packet   * @txed: number of Txed frames in this batch   * @txed_2_done: number of Acked frames in this batch + * @reduced_txp: power reduced according to TPC. This is the actual value and + *	not a copy from the LQ command. Thus, if not the first rate was used + *	for Tx-ing then this value will be set to 0 by FW.   */  struct iwl_mvm_ba_notif {  	__le32 sta_addr_lo32; @@ -524,7 +527,8 @@ struct iwl_mvm_ba_notif {  	__le16 scd_ssn;  	u8 txed;  	u8 txed_2_done; -	__le16 reserved1; +	u8 reduced_txp; +	u8 reserved1;  } __packed;  /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 4ed5180c547b..0ccc697fef76 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -107,7 +107,7 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)  				    sizeof(tx_ant_cmd), &tx_ant_cmd);  } -static void iwl_free_fw_paging(struct iwl_mvm *mvm) +void iwl_free_fw_paging(struct iwl_mvm *mvm)  {  	int i; @@ -127,6 +127,8 @@ static void iwl_free_fw_paging(struct iwl_mvm *mvm)  			     get_order(mvm->fw_paging_db[i].fw_paging_size));  	}  	kfree(mvm->trans->paging_download_buf); +	mvm->trans->paging_download_buf = NULL; +  	memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db));  } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 5f3ac8cccf49..ff7c6df9f941 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1225,6 +1225,9 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,  void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,  					      struct iwl_rx_cmd_buffer *rxb); +/* Paging */ +void iwl_free_fw_paging(struct iwl_mvm *mvm); +  /* MVM debugfs */  #ifdef CONFIG_IWLWIFI_DEBUGFS  int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 89ea70deeb84..e80be9a59520 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -684,6 +684,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)  	for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++)  		kfree(mvm->nvm_sections[i].data); +	iwl_free_fw_paging(mvm); +  	iwl_mvm_tof_clean(mvm);  	ieee80211_free_hw(mvm->hw); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 7bb6fd0e4391..94caa88df442 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -2,6 +2,7 @@   *   * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH   *   * This program is free software; you can redistribute it and/or modify it   * under the terms of version 2 of the GNU General Public License as @@ -724,14 +725,28 @@ static int _rs_collect_tx_data(struct iwl_mvm *mvm,  	return 0;  } -static int rs_collect_tx_data(struct iwl_mvm *mvm, -			      struct iwl_lq_sta *lq_sta, -			      struct iwl_scale_tbl_info *tbl, -			      int scale_index, int attempts, int successes, -			      u8 reduced_txp) +static int rs_collect_tpc_data(struct iwl_mvm *mvm, +			       struct iwl_lq_sta *lq_sta, +			       struct iwl_scale_tbl_info *tbl, +			       int scale_index, int attempts, int successes, +			       u8 reduced_txp) +{ +	struct iwl_rate_scale_data *window = NULL; + +	if (WARN_ON_ONCE(reduced_txp > TPC_MAX_REDUCTION)) +		return -EINVAL; + +	window = &tbl->tpc_win[reduced_txp]; +	return  _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes, +				    window); +} + +static int rs_collect_tlc_data(struct iwl_mvm *mvm, +			       struct iwl_lq_sta *lq_sta, +			       struct iwl_scale_tbl_info *tbl, +			       int scale_index, int attempts, int successes)  {  	struct iwl_rate_scale_data *window = NULL; -	int ret;  	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)  		return -EINVAL; @@ -745,16 +760,6 @@ static int rs_collect_tx_data(struct iwl_mvm *mvm,  	/* Select window for current tx bit rate */  	window = &(tbl->win[scale_index]); - -	ret = _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes, -				  window); -	if (ret) -		return ret; - -	if (WARN_ON_ONCE(reduced_txp > TPC_MAX_REDUCTION)) -		return -EINVAL; - -	window = &tbl->tpc_win[reduced_txp];  	return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,  				   window);  } @@ -1301,17 +1306,30 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  	 * first index into rate scale table.  	 */  	if (info->flags & IEEE80211_TX_STAT_AMPDU) { -		/* ampdu_ack_len = 0 marks no BA was received. In this case -		 * treat it as a single frame loss as we don't want the success -		 * ratio to dip too quickly because a BA wasn't received +		rs_collect_tpc_data(mvm, lq_sta, curr_tbl, lq_rate.index, +				    info->status.ampdu_len, +				    info->status.ampdu_ack_len, +				    reduced_txp); + +		/* ampdu_ack_len = 0 marks no BA was received. For TLC, treat +		 * it as a single frame loss as we don't want the success ratio +		 * to dip too quickly because a BA wasn't received. +		 * For TPC, there's no need for this optimisation since we want +		 * to recover very quickly from a bad power reduction and, +		 * therefore we'd like the success ratio to get an immediate hit +		 * when failing to get a BA, so we'd switch back to a lower or +		 * zero power reduction. When FW transmits agg with a rate +		 * different from the initial rate, it will not use reduced txp +		 * and will send BA notification twice (one empty with reduced +		 * txp equal to the value from LQ and one with reduced txp 0). +		 * We need to update counters for each txp level accordingly.  		 */  		if (info->status.ampdu_ack_len == 0)  			info->status.ampdu_len = 1; -		rs_collect_tx_data(mvm, lq_sta, curr_tbl, lq_rate.index, -				   info->status.ampdu_len, -				   info->status.ampdu_ack_len, -				   reduced_txp); +		rs_collect_tlc_data(mvm, lq_sta, curr_tbl, lq_rate.index, +				    info->status.ampdu_len, +				    info->status.ampdu_ack_len);  		/* Update success/fail counts if not searching for new mode */  		if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { @@ -1344,9 +1362,13 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  			else  				continue; -			rs_collect_tx_data(mvm, lq_sta, tmp_tbl, lq_rate.index, -					   1, i < retries ? 0 : legacy_success, -					   reduced_txp); +			rs_collect_tpc_data(mvm, lq_sta, tmp_tbl, +					    lq_rate.index, 1, +					    i < retries ? 0 : legacy_success, +					    reduced_txp); +			rs_collect_tlc_data(mvm, lq_sta, tmp_tbl, +					    lq_rate.index, 1, +					    i < retries ? 0 : legacy_success);  		}  		/* Update success/fail counts if not searching for new mode */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 9a15642f80dd..ea1e177c2ea1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1298,6 +1298,10 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,  		return -EBUSY;  	} +	/* we don't support "match all" in the firmware */ +	if (!req->n_match_sets) +		return -EOPNOTSUPP; +  	ret = iwl_mvm_check_running_scans(mvm, type);  	if (ret)  		return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 8bf48a7d0f4e..a040edc55057 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -423,6 +423,15 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)  		return -1;  	} +	/* +	 * Increase the pending frames counter, so that later when a reply comes +	 * in and the counter is decreased - we don't start getting negative +	 * values. +	 * Note that we don't need to make sure it isn't agg'd, since we're +	 * TXing non-sta +	 */ +	atomic_inc(&mvm->pending_frames[sta_id]); +  	return 0;  } @@ -1029,7 +1038,6 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,  		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);  		mvmsta->tid_data[tid].rate_n_flags =  			le32_to_cpu(tx_resp->initial_rate); -		mvmsta->tid_data[tid].reduced_tpc = tx_resp->reduced_tpc;  		mvmsta->tid_data[tid].tx_time =  			le16_to_cpu(tx_resp->wireless_media_time);  	} @@ -1060,7 +1068,7 @@ static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info,  	/* TODO: not accounted if the whole A-MPDU failed */  	info->status.tx_time = tid_data->tx_time;  	info->status.status_driver_data[0] = -		(void *)(uintptr_t)tid_data->reduced_tpc; +		(void *)(uintptr_t)ba_notif->reduced_txp;  	info->status.status_driver_data[1] =  		(void *)(uintptr_t)tid_data->rate_n_flags;  } @@ -1133,6 +1141,8 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  			   scd_flow, ba_resp_scd_ssn, ba_notif->txed,  			   ba_notif->txed_2_done); +	IWL_DEBUG_TX_REPLY(mvm, "reduced txp from ba notif %d\n", +			   ba_notif->reduced_txp);  	tid_data->next_reclaimed = ba_resp_scd_ssn;  	iwl_mvm_check_ratid_empty(mvm, sta, tid); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 6261a68cae90..00335ea6b3eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -378,7 +378,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = {  	{IWL_PCI_DEVICE(0x3165, 0x8110, iwl3165_2ac_cfg)},  /* 3168 Series */ +	{IWL_PCI_DEVICE(0x24FB, 0x2010, iwl3168_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24FB, 0x2110, iwl3168_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x24FB, 0x2050, iwl3168_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x24FB, 0x2150, iwl3168_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24FB, 0x0000, iwl3168_2ac_cfg)},  /* 7265 Series */ @@ -475,6 +478,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {  	{IWL_PCI_DEVICE(0x24F3, 0x0000, iwl8265_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24FD, 0x0010, iwl8265_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24FD, 0x8010, iwl8265_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x24FD, 0x0810, iwl8265_2ac_cfg)},  /* 9000 Series */  	{IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)}, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index cc3888e2700d..73c95594eabe 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -490,6 +490,15 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)  	iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);  } +static inline void iwl_enable_fw_load_int(struct iwl_trans *trans) +{ +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + +	IWL_DEBUG_ISR(trans, "Enabling FW load interrupt\n"); +	trans_pcie->inta_mask = CSR_INT_BIT_FH_TX; +	iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); +} +  static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index ccafbd8cf4b3..152cf9ad9566 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1438,9 +1438,11 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)  			 inta & ~trans_pcie->inta_mask);  	} -	/* Re-enable all interrupts */ -	/* only Re-enable if disabled by irq */ -	if (test_bit(STATUS_INT_ENABLED, &trans->status)) +	/* we are loading the firmware, enable FH_TX interrupt only */ +	if (handled & CSR_INT_BIT_FH_TX) +		iwl_enable_fw_load_int(trans); +	/* only Re-enable all interrupt if disabled by irq */ +	else if (test_bit(STATUS_INT_ENABLED, &trans->status))  		iwl_enable_interrupts(trans);  	/* Re-enable RF_KILL if it occurred */  	else if (handled & CSR_INT_BIT_RF_KILL) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index d60a467a983c..5a854c609477 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1021,82 +1021,6 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans,  					       &first_ucode_section);  } -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); -	bool hw_rfkill; -	int ret; - -	mutex_lock(&trans_pcie->mutex); - -	/* Someone called stop_device, don't try to start_fw */ -	if (trans_pcie->is_down) { -		IWL_WARN(trans, -			 "Can't start_fw since the HW hasn't been started\n"); -		ret = EIO; -		goto out; -	} - -	/* This may fail if AMT took ownership of the device */ -	if (iwl_pcie_prepare_card_hw(trans)) { -		IWL_WARN(trans, "Exit HW not ready\n"); -		ret = -EIO; -		goto out; -	} - -	iwl_enable_rfkill_int(trans); - -	/* If platform's RF_KILL switch is NOT set to KILL */ -	hw_rfkill = iwl_is_rfkill_set(trans); -	if (hw_rfkill) -		set_bit(STATUS_RFKILL, &trans->status); -	else -		clear_bit(STATUS_RFKILL, &trans->status); -	iwl_trans_pcie_rf_kill(trans, hw_rfkill); -	if (hw_rfkill && !run_in_rfkill) { -		ret = -ERFKILL; -		goto out; -	} - -	iwl_write32(trans, CSR_INT, 0xFFFFFFFF); - -	ret = iwl_pcie_nic_init(trans); -	if (ret) { -		IWL_ERR(trans, "Unable to init nic\n"); -		goto out; -	} - -	/* 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, -		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - -	/* clear (again), then enable host interrupts */ -	iwl_write32(trans, CSR_INT, 0xFFFFFFFF); -	iwl_enable_interrupts(trans); - -	/* really 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, CSR_UCODE_SW_BIT_RFKILL); - -	/* Load the given image to the HW */ -	if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) -		ret = iwl_pcie_load_given_ucode_8000(trans, fw); -	else -		ret = iwl_pcie_load_given_ucode(trans, fw); - -out: -	mutex_unlock(&trans_pcie->mutex); -	return ret; -} - -static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) -{ -	iwl_pcie_reset_ict(trans); -	iwl_pcie_tx_start(trans, scd_addr); -} -  static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1127,7 +1051,8 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)  	 * already dead.  	 */  	if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { -		IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n"); +		IWL_DEBUG_INFO(trans, +			       "DEVICE_ENABLED bit was set and is now cleared\n");  		iwl_pcie_tx_stop(trans);  		iwl_pcie_rx_stop(trans); @@ -1161,7 +1086,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)  	iwl_disable_interrupts(trans);  	spin_unlock(&trans_pcie->irq_lock); -  	/* clear all status bits */  	clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);  	clear_bit(STATUS_INT_ENABLED, &trans->status); @@ -1194,10 +1118,116 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)  	if (hw_rfkill != was_hw_rfkill)  		iwl_trans_pcie_rf_kill(trans, hw_rfkill); -	/* re-take ownership to prevent other users from stealing the deivce */ +	/* re-take ownership to prevent other users from stealing the device */  	iwl_pcie_prepare_card_hw(trans);  } +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); +	bool hw_rfkill; +	int ret; + +	/* This may fail if AMT took ownership of the device */ +	if (iwl_pcie_prepare_card_hw(trans)) { +		IWL_WARN(trans, "Exit HW not ready\n"); +		ret = -EIO; +		goto out; +	} + +	iwl_enable_rfkill_int(trans); + +	iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + +	/* +	 * We enabled the RF-Kill interrupt and the handler may very +	 * well be running. Disable the interrupts to make sure no other +	 * interrupt can be fired. +	 */ +	iwl_disable_interrupts(trans); + +	/* Make sure it finished running */ +	synchronize_irq(trans_pcie->pci_dev->irq); + +	mutex_lock(&trans_pcie->mutex); + +	/* If platform's RF_KILL switch is NOT set to KILL */ +	hw_rfkill = iwl_is_rfkill_set(trans); +	if (hw_rfkill) +		set_bit(STATUS_RFKILL, &trans->status); +	else +		clear_bit(STATUS_RFKILL, &trans->status); +	iwl_trans_pcie_rf_kill(trans, hw_rfkill); +	if (hw_rfkill && !run_in_rfkill) { +		ret = -ERFKILL; +		goto out; +	} + +	/* Someone called stop_device, don't try to start_fw */ +	if (trans_pcie->is_down) { +		IWL_WARN(trans, +			 "Can't start_fw since the HW hasn't been started\n"); +		ret = -EIO; +		goto out; +	} + +	/* 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, +		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + +	/* clear (again), then enable host interrupts */ +	iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + +	ret = iwl_pcie_nic_init(trans); +	if (ret) { +		IWL_ERR(trans, "Unable to init nic\n"); +		goto out; +	} + +	/* +	 * Now, we load the firmware and don't want to be interrupted, even +	 * by the RF-Kill interrupt (hence mask all the interrupt besides the +	 * FH_TX interrupt which is needed to load the firmware). If the +	 * RF-Kill switch is toggled, we will find out after having loaded +	 * the firmware and return the proper value to the caller. +	 */ +	iwl_enable_fw_load_int(trans); + +	/* really 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, CSR_UCODE_SW_BIT_RFKILL); + +	/* Load the given image to the HW */ +	if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) +		ret = iwl_pcie_load_given_ucode_8000(trans, fw); +	else +		ret = iwl_pcie_load_given_ucode(trans, fw); +	iwl_enable_interrupts(trans); + +	/* re-check RF-Kill state since we may have missed the interrupt */ +	hw_rfkill = iwl_is_rfkill_set(trans); +	if (hw_rfkill) +		set_bit(STATUS_RFKILL, &trans->status); +	else +		clear_bit(STATUS_RFKILL, &trans->status); + +	iwl_trans_pcie_rf_kill(trans, hw_rfkill); +	if (hw_rfkill && !run_in_rfkill) +		ret = -ERFKILL; + +out: +	mutex_unlock(&trans_pcie->mutex); +	return ret; +} + +static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) +{ +	iwl_pcie_reset_ict(trans); +	iwl_pcie_tx_start(trans, scd_addr); +} +  static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); diff --git a/drivers/net/wireless/intersil/orinoco/mic.c b/drivers/net/wireless/intersil/orinoco/mic.c index fce4a843e656..bc7397d709d3 100644 --- a/drivers/net/wireless/intersil/orinoco/mic.c +++ b/drivers/net/wireless/intersil/orinoco/mic.c @@ -6,7 +6,7 @@  #include <linux/string.h>  #include <linux/if_ether.h>  #include <linux/scatterlist.h> -#include <linux/crypto.h> +#include <crypto/hash.h>  #include "orinoco.h"  #include "mic.h" @@ -16,7 +16,8 @@  /********************************************************************/  int orinoco_mic_init(struct orinoco_private *priv)  { -	priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); +	priv->tx_tfm_mic = crypto_alloc_ahash("michael_mic", 0, +					      CRYPTO_ALG_ASYNC);  	if (IS_ERR(priv->tx_tfm_mic)) {  		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "  		       "crypto API michael_mic\n"); @@ -24,7 +25,8 @@ int orinoco_mic_init(struct orinoco_private *priv)  		return -ENOMEM;  	} -	priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); +	priv->rx_tfm_mic = crypto_alloc_ahash("michael_mic", 0, +					      CRYPTO_ALG_ASYNC);  	if (IS_ERR(priv->rx_tfm_mic)) {  		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "  		       "crypto API michael_mic\n"); @@ -38,18 +40,19 @@ int orinoco_mic_init(struct orinoco_private *priv)  void orinoco_mic_free(struct orinoco_private *priv)  {  	if (priv->tx_tfm_mic) -		crypto_free_hash(priv->tx_tfm_mic); +		crypto_free_ahash(priv->tx_tfm_mic);  	if (priv->rx_tfm_mic) -		crypto_free_hash(priv->rx_tfm_mic); +		crypto_free_ahash(priv->rx_tfm_mic);  } -int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key, +int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,  		u8 *da, u8 *sa, u8 priority,  		u8 *data, size_t data_len, u8 *mic)  { -	struct hash_desc desc; +	AHASH_REQUEST_ON_STACK(req, tfm_michael);  	struct scatterlist sg[2];  	u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ +	int err;  	if (tfm_michael == NULL) {  		printk(KERN_WARNING "orinoco_mic: tfm_michael == NULL\n"); @@ -69,11 +72,13 @@ int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,  	sg_set_buf(&sg[0], hdr, sizeof(hdr));  	sg_set_buf(&sg[1], data, data_len); -	if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN)) +	if (crypto_ahash_setkey(tfm_michael, key, MIC_KEYLEN))  		return -1; -	desc.tfm = tfm_michael; -	desc.flags = 0; -	return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr), -				  mic); +	ahash_request_set_tfm(req, tfm_michael); +	ahash_request_set_callback(req, 0, NULL, NULL); +	ahash_request_set_crypt(req, sg, mic, data_len + sizeof(hdr)); +	err = crypto_ahash_digest(req); +	ahash_request_zero(req); +	return err;  } diff --git a/drivers/net/wireless/intersil/orinoco/mic.h b/drivers/net/wireless/intersil/orinoco/mic.h index 04d05bc566d6..ce731d05cc98 100644 --- a/drivers/net/wireless/intersil/orinoco/mic.h +++ b/drivers/net/wireless/intersil/orinoco/mic.h @@ -11,11 +11,11 @@  /* Forward declarations */  struct orinoco_private; -struct crypto_hash; +struct crypto_ahash;  int orinoco_mic_init(struct orinoco_private *priv);  void orinoco_mic_free(struct orinoco_private *priv); -int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key, +int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,  		u8 *da, u8 *sa, u8 priority,  		u8 *data, size_t data_len, u8 *mic); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco.h b/drivers/net/wireless/intersil/orinoco/orinoco.h index eebd2be21ee9..2f0c84b1c440 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco.h +++ b/drivers/net/wireless/intersil/orinoco/orinoco.h @@ -152,8 +152,8 @@ struct orinoco_private {  	u8 *wpa_ie;  	int wpa_ie_len; -	struct crypto_hash *rx_tfm_mic; -	struct crypto_hash *tx_tfm_mic; +	struct crypto_ahash *rx_tfm_mic; +	struct crypto_ahash *tx_tfm_mic;  	unsigned int wpa_enabled:1;  	unsigned int tkip_cm_active:1; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c32889a1e39c..a28414c50edf 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -991,7 +991,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,  		goto nla_put_failure;  	} -	if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, hdr->addr2)) +	if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, +		    ETH_ALEN, data->addresses[1].addr))  		goto nla_put_failure;  	/* We get the skb->data */ @@ -2736,7 +2737,7 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)  	spin_lock_bh(&hwsim_radio_lock);  	list_for_each_entry(data, &hwsim_radios, list) { -		if (mac80211_hwsim_addr_match(data, addr)) { +		if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) {  			_found = true;  			break;  		} diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index 0b9c580af988..2eff989c6d9f 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -880,14 +880,12 @@ mwifiex_reset_write(struct file *file,  {  	struct mwifiex_private *priv = file->private_data;  	struct mwifiex_adapter *adapter = priv->adapter; -	char cmd;  	bool result; +	int rc; -	if (copy_from_user(&cmd, ubuf, sizeof(cmd))) -		return -EFAULT; - -	if (strtobool(&cmd, &result)) -		return -EINVAL; +	rc = kstrtobool_from_user(ubuf, count, &result); +	if (rc) +		return rc;  	if (!result)  		return -EINVAL; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 9a3966cd6fbe..155f343981fe 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -273,8 +273,10 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev,  			   !(filter_flags & FIF_PLCPFAIL));  	rt2x00_set_field32(®, RXCSR0_DROP_CONTROL,  			   !(filter_flags & FIF_CONTROL)); -	rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 1); +	rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));  	rt2x00_set_field32(®, RXCSR0_DROP_TODS, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) &&  			   !rt2x00dev->intf_ap_count);  	rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);  	rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index 1a6740b4d396..2553cdd74066 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -274,8 +274,10 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev,  			   !(filter_flags & FIF_PLCPFAIL));  	rt2x00_set_field32(®, RXCSR0_DROP_CONTROL,  			   !(filter_flags & FIF_CONTROL)); -	rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 1); +	rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));  	rt2x00_set_field32(®, RXCSR0_DROP_TODS, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) &&  			   !rt2x00dev->intf_ap_count);  	rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);  	rt2x00_set_field32(®, RXCSR0_DROP_MCAST, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index d26018f30b7d..2d64611de300 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -437,8 +437,10 @@ static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev,  			   !(filter_flags & FIF_PLCPFAIL));  	rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL,  			   !(filter_flags & FIF_CONTROL)); -	rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, 1); +	rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));  	rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) &&  			   !rt2x00dev->intf_ap_count);  	rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1);  	rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 9733b31a780d..a26afcab03ed 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1490,7 +1490,8 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,  			   !(filter_flags & FIF_FCSFAIL));  	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR,  			   !(filter_flags & FIF_PLCPFAIL)); -	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, 1); +	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));  	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);  	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1);  	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 3282ddb766f4..26427140a963 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -669,6 +669,7 @@ enum rt2x00_state_flags {  	CONFIG_POWERSAVING,  	CONFIG_HT_DISABLED,  	CONFIG_QOS_DISABLED, +	CONFIG_MONITORING,  	/*  	 * Mark we currently are sequentially reading TX_STA_FIFO register diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c index 7e8bb1198ae9..6a1f508d472f 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c @@ -277,6 +277,11 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,  	else  		clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); +	if (conf->flags & IEEE80211_CONF_MONITOR) +		set_bit(CONFIG_MONITORING, &rt2x00dev->flags); +	else +		clear_bit(CONFIG_MONITORING, &rt2x00dev->flags); +  	rt2x00dev->curr_band = conf->chandef.chan->band;  	rt2x00dev->curr_freq = conf->chandef.chan->center_freq;  	rt2x00dev->tx_power = conf->power_level; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 3c26ee65a415..13da95a24cf7 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -385,11 +385,6 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,  			*total_flags |= FIF_PSPOLL;  	} -	/* -	 * Check if there is any work left for us. -	 */ -	if (rt2x00dev->packet_filter == *total_flags) -		return;  	rt2x00dev->packet_filter = *total_flags;  	rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index c0e730ea1b69..24a3436ef952 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -530,8 +530,10 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,  			   !(filter_flags & FIF_PLCPFAIL));  	rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,  			   !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); -	rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 1); +	rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));  	rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) &&  			   !rt2x00dev->intf_ap_count);  	rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);  	rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index 7081e13b4fd6..7bbc86931168 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -480,8 +480,10 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,  			   !(filter_flags & FIF_PLCPFAIL));  	rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,  			   !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); -	rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 1); +	rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));  	rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, +			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) &&  			   !rt2x00dev->intf_ap_count);  	rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);  	rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c index 74c14ce28238..28f7010e7108 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rc.c +++ b/drivers/net/wireless/realtek/rtlwifi/rc.c @@ -138,6 +138,11 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,  		    ((wireless_mode == WIRELESS_MODE_N_5G) ||  		     (wireless_mode == WIRELESS_MODE_N_24G)))  			rate->flags |= IEEE80211_TX_RC_MCS; +		if (sta && sta->vht_cap.vht_supported && +		    (wireless_mode == WIRELESS_MODE_AC_5G || +		     wireless_mode == WIRELESS_MODE_AC_24G || +		     wireless_mode == WIRELESS_MODE_AC_ONLY)) +			rate->flags |= IEEE80211_TX_RC_VHT_MCS;  	}  } diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index a62bf0a65c32..5be34118e0af 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -351,7 +351,6 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(  	case COUNTRY_CODE_SPAIN:  	case COUNTRY_CODE_FRANCE:  	case COUNTRY_CODE_ISRAEL: -	case COUNTRY_CODE_WORLD_WIDE_13:  		return &rtl_regdom_12_13;  	case COUNTRY_CODE_MKK:  	case COUNTRY_CODE_MKK1: @@ -360,6 +359,7 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(  		return &rtl_regdom_14_60_64;  	case COUNTRY_CODE_GLOBAL_DOMAIN:  		return &rtl_regdom_14; +	case COUNTRY_CODE_WORLD_WIDE_13:  	case COUNTRY_CODE_WORLD_WIDE_13_5G_ALL:  		return &rtl_regdom_12_13_5g_all;  	default: diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c index b57cfd965196..95dcbff4673b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c @@ -626,7 +626,7 @@ static void rtl8821ae_dm_find_minimum_rssi(struct ieee80211_hw *hw)  		rtl_dm_dig->min_undec_pwdb_for_dm =  		    rtlpriv->dm.entry_min_undec_sm_pwdb;  		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, -			 "AP Ext Port or disconnet PWDB = 0x%x\n", +			 "AP Ext Port or disconnect PWDB = 0x%x\n",  			 rtl_dm_dig->min_undec_pwdb_for_dm);  	}  	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, diff --git a/drivers/net/wireless/ti/wlcore/io.c b/drivers/net/wireless/ti/wlcore/io.c index 9ac118e727e9..564ca750c5ee 100644 --- a/drivers/net/wireless/ti/wlcore/io.c +++ b/drivers/net/wireless/ti/wlcore/io.c @@ -175,14 +175,14 @@ int wlcore_set_partition(struct wl1271 *wl,  	if (ret < 0)  		goto out; +	/* We don't need the size of the last partition, as it is +	 * automatically calculated based on the total memory size and +	 * the sizes of the previous partitions. +	 */  	ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);  	if (ret < 0)  		goto out; -	ret = wlcore_raw_write32(wl, HW_PART3_SIZE_ADDR, p->mem3.size); -	if (ret < 0) -		goto out; -  out:  	return ret;  } diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index 6c257b54f415..10cf3747694d 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h @@ -36,8 +36,8 @@  #define HW_PART1_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 12)  #define HW_PART2_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR + 16)  #define HW_PART2_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 20) -#define HW_PART3_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR + 24) -#define HW_PART3_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 28) +#define HW_PART3_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 24) +  #define HW_ACCESS_REGISTER_SIZE         4  #define HW_ACCESS_PRAM_MAX_RANGE	0x3c000 diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index d6abf191122a..96ccd4e943db 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -364,6 +364,7 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue)  	RING_IDX cons, prod;  	unsigned short id;  	struct sk_buff *skb; +	bool more_to_do;  	BUG_ON(!netif_carrier_ok(queue->info->netdev)); @@ -398,18 +399,8 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue)  		queue->tx.rsp_cons = prod; -		/* -		 * Set a new event, then check for race with update of tx_cons. -		 * Note that it is essential to schedule a callback, no matter -		 * how few buffers are pending. Even if there is space in the -		 * transmit ring, higher layers may be blocked because too much -		 * data is outstanding: in such cases notification from Xen is -		 * likely to be the only kick that we'll get. -		 */ -		queue->tx.sring->rsp_event = -			prod + ((queue->tx.sring->req_prod - prod) >> 1) + 1; -		mb();		/* update shared area */ -	} while ((cons == prod) && (prod != queue->tx.sring->rsp_prod)); +		RING_FINAL_CHECK_FOR_RESPONSES(&queue->tx, more_to_do); +	} while (more_to_do);  	xennet_maybe_wake_tx(queue);  } | 
