lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20080515121427.GJ28241@solarflare.com>
Date:	Thu, 15 May 2008 13:14:28 +0100
From:	Ben Hutchings <bhutchings@...arflare.com>
To:	Subbu Seetharaman <subbus@...verengines.com>
Cc:	netdev@...r.kernel.org
Subject: Re: [PATCH 2/15] BE NIC driver - interrupt, ethtool, stack i/f functions

Subbu Seetharaman wrote:
> +#define NET_DEV_STATS_LEN \
> +	(sizeof(struct net_device_stats)/sizeof(unsigned long))
> +#define BENET_STATS_LEN  sizeof(benet_gstrings_stats) / ETH_GSTRING_LEN

You can use the ARRAY_SIZE() macro for this.

> +
> +static void
> +be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
> +{
> +	struct bni_net_object *pnob = netdev->priv;
> +	struct be_adapter *adapter = OSM_NOB(pnob)->adapter;
> +
> +	strncpy(drvinfo->driver, be_driver_name, 32);
> +	strncpy(drvinfo->version, be_drvr_ver, 32);
> +	strncpy(drvinfo->fw_version, be_fw_ver, 32);
> +	strcpy(drvinfo->bus_info, pci_name(adapter->pdev));

You can use ETHTOOL_BUSINFO_LEN as a limit here, though it's longer than
the pci_name() string can currently be.

> +static int
> +be_set_coalesce(struct net_device *netdev,
> +		struct ethtool_coalesce *coalesce)
> +{
> +	struct bni_net_object *pnob = netdev->priv;
> +	struct be_adapter *adapter = OSM_NOB(pnob)->adapter;
> +	u32 max, min, cur;
> +
> +	adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
> +	if (adapter->max_rx_coal < 0)
> +		adapter->max_rx_coal = 0;

rx_max_coalesced_frames is unsigned.  If you make max_rx_coal unsigned too
then you don't need to worry about this case.

> +	if (adapter->max_rx_coal >= BE_LRO_MAX_PKTS)
> +		adapter->max_rx_coal = BE_LRO_MAX_PKTS;

Why are you applying an LRO limit here?  This is supposed to control
interrupt coalescing.

> +static void
> +be_get_ethtool_stats(struct net_device *netdev,
> +		     struct ethtool_stats *stats, uint64_t *data)
> +{
> +	struct bni_net_object *pnob = netdev->priv;
> +	struct be_adapter *adapter = OSM_NOB(pnob)->adapter;
> +	int i;
> +
> +	data[0] = adapter->pdev->irq;

That's a very strange way to expose the IRQ number.

> +static void
> +be_get_pauseparam(struct net_device *netdev,
> +		  struct ethtool_pauseparam *ecmd)
> +{
> +	struct bni_net_object *pnob = netdev->priv;
> +	bool rxfc = FALSE;
> +	bool txfc = FALSE;
> +	BESTATUS status;
> +	if (ecmd->cmd != ETHTOOL_GPAUSEPARAM)
> +		return;

How could this happen?

> +	status = bni_get_flow_ctl(&pnob->fn_obj, &txfc, &rxfc);
> +	if (status != BE_SUCCESS)
> +		printk(KERN_WARNING "Unable to get pause frame settings\n");
> +
> +	if (txfc == TRUE)
> +		ecmd->tx_pause = 1;
> +	else
> +		ecmd->tx_pause = 0;
> +
> +	if (rxfc == TRUE)
> +		ecmd->rx_pause = 1;
> +	else
> +		ecmd->rx_pause = 0;
> +
> +	/* Always setting autoneg to TRUE */
> +	ecmd->autoneg = 1;
> +
> +	return;

Don't use return here; it's redundant.

> +}
> +
> +static int
> +be_set_pauseparam(struct net_device *netdev,
> +		  struct ethtool_pauseparam *ecmd)
> +{
[...]
> +	status = bni_set_flow_ctll(&pnob->fn_obj, txfc, rxfc);
> +	if (status != BE_SUCCESS)
> +		printk(KERN_ERR "Unable to set pause frame settings\n");
> +	return 0;

Don't printk() the error, return an error code.

> +}
> +
> +struct ethtool_ops be_ethtool_ops = {
> +	.get_settings = be_get_settings,
> +	.get_drvinfo = be_get_drvinfo,
> +	.get_link = ethtool_op_get_link,
> +	.get_coalesce = be_get_coalesce,
> +	.set_coalesce = be_set_coalesce,
> +	.get_ringparam = be_get_ringparam,
> +	.get_pauseparam = be_get_pauseparam,
> +	.set_pauseparam = be_set_pauseparam,
> +	.get_rx_csum = be_get_rx_csum,	/*Yes */
> +	.set_rx_csum = be_set_rx_csum,
> +	.get_tx_csum = ethtool_op_get_tx_csum,	/*Yes */
> +	.set_tx_csum = ethtool_op_set_tx_csum,	/*Yes */
> +	.get_sg = ethtool_op_get_sg,	/*Yes */
> +	.set_sg = ethtool_op_set_sg,	/*Yes */

These comments aren't at all helpful.

> --- /dev/null
> +++ b/drivers/net/benet/be_int.c
[...]
> + * The full GNU General Public License is included in this distribution
> + * in the file called GPL.

Actually it's called COPYING.

> +#ifdef CONFIG_BENET_NAPI
> +#define NETIF_RX(skb) netif_receive_skb(skb);
> +#else
> +#define NETIF_RX(skb) netif_rx(skb);
> +#endif

Don't put semi-colons on the end of macros.

> +
> +/*
> + * adds additional receive frags indicated by BE starting from given
> + * frag index (fi) to specified skb's frag list
> + */
> +static inline void
> +add_skb_frags(struct bni_net_object *pnob, struct sk_buff *skb,
> +		int nresid, u32 fi)

Probably shouldn't be declared inline - the compiler can work that out.
(And yes, this is hypocrisy on my part.)

> +{
> +	struct be_adapter *adapter = OSM_NOB(pnob)->adapter;
> +	u32 sk_frag_idx, n;
> +	struct be_rx_page_info *rx_page_info;
> +	u32 frag_sz = pnob->rx_buf_size;
> +
> +	sk_frag_idx = skb_shinfo(skb)->nr_frags;
> +	while (nresid) {
> +		fi = (fi + 1) % pnob->rx_q_len; /* frag index */

If rx_q_len is always a power of two, you can mask and avoid a division
(relatively slow).

> +/*
> + * This function processes incoming nic packets over various Rx queues.
> + * This function takes the adapter, the current Rx status descriptor
> + * entry and the Rx completion queue ID as argument.
> + */
> +static inline int process_nic_rx_completion(struct bni_net_object *pnob,
> +					    struct ETH_RX_COMPL_AMAP *rxcp)
> +{
> +	struct be_adapter *adapter = OSM_NOB(pnob)->adapter;
> +	struct sk_buff *skb;
> +	int udpcksm, tcpcksm;
> +	int n, fi;
> +	int nresid;
> +	unsigned int frag_sz = pnob->rx_buf_size;
> +	u8 *va;
> +	struct be_rx_page_info *rx_page_info;
> +	u32 numfrags, vtp, vtm, vlan_tag, pktsize;
> +
> +	fi  = AMAP_GET_BITS_PTR(ETH_RX_COMPL, fragndx, rxcp);
> +	SA_ASSERT(fi < (int)pnob->rx_q_len);
> +	SA_ASSERT(fi >= 0);

You should use BUG_ON, not your own assertion macros.

> +	rx_page_info = (struct be_rx_page_info *) pnob->rx_ctxt[fi];
> +	SA_ASSERT(rx_page_info->page);
> +	pnob->rx_ctxt[fi] = (void *)NULL;

The cast is redundant.

> +	sa_atomic_decrement(&pnob->rx_q_posted);

Why not atomic_dec()?

[...]
> +#ifdef CONFIG_INET_LRO
[... 127 lines ...]
> +#else
> +		process_nic_rx_completion(pnob, rxcp);
> +#endif

It looks like you should create a separate function for the LRO case.

> +static void process_bcast_rx_completion(struct bni_net_object *pnob)
> +{
> +	struct be_adapter *adapter = OSM_NOB(pnob)->adapter;
> +	struct ETH_RX_COMPL_AMAP *rxcp;
> +
> +	u32 nc = 0;
> +
> +	adapter->be_stat.bes_bcrx_events++;
> +
> +	nc = 0;

Redundant assignment.

> +/*
> + * posts receive buffers to the Eth receive queue.
> + */
> +void post_eth_rx_buffs(struct bni_net_object *pnob)
> +{
> +	struct be_adapter *adapter = OSM_NOB(pnob)->adapter;
> +	u32 num_bufs, r;
> +	u64 busaddr = 0, tmp_pa;
> +	u32 max_bufs, pg_hd;
> +	u32 frag_size;
> +	struct BNI_RECV_BUFFER *rxbp;
> +	SA_LIST_ENTRY rxbl;
> +	struct be_rx_page_info *rx_page_info;
> +	struct page *page = NULL;
> +	u32 page_order = 0;
> +	gfp_t alloc_flags = (gfp_t)GFP_ATOMIC;

Redundant cast.  We all know what GFP_ATOMIC is used for and the compiler
is happy to convert it.

> +	SA_ASSERT(adapter);
> +
> +	max_bufs = (u32) 64;	/* should be even # <= 255. */
> +	SA_ASSERT(max_bufs < 255 && (max_bufs & 1) == 0);

Why are you making an assertion about a constant?  Perhaps you want
something like:

#define MAX_POST_RX_BUFS 64 /* should be even # <= 255. */

and then you can use a compile-time assertion:

	BUILD_BUG_ON(MAX_POST_RX_BUFS > 255 || MAX_POST_RX_BUFS & 1);

> +	frag_size = pnob->rx_buf_size;
> +
> +	if (frag_size == 8192) {
> +		page_order = 1;
> +		alloc_flags |= (gfp_t)__GFP_COMP;
> +	}

You're assuming PAGE_SIZE == 4096.

> +#ifdef CONFIG_BENET_NAPI
> +/*
> + * Poll function called by NAPI with a work budget.
> + * We process as many UC. BC and MC receive completions
> + * as the budget allows and return the actual number of
> + * RX ststutses processed.
> + */
> +int be_poll(struct napi_struct *napi, int budget)
> +{
> +	struct net_device *netdev = napi->dev;
> +	struct bni_net_object *pnob = (struct bni_net_object *) netdev->priv;
> +	struct be_adapter *adapter = (struct be_adapter *)
> +						OSM_NOB(pnob)->adapter;
> +	u32 work_done;
> +
> +	adapter->be_stat.bes_polls++;
> +	OSM_NOB(pnob)->work_quota = budget;
> +	process_ucast_rx_completion(pnob);
> +	process_bcast_rx_completion(pnob);
> +	if (pnob->rx_q_posted < 900)
> +		post_eth_rx_buffs(pnob);
> +
> +	work_done = (budget - OSM_NOB(pnob)->work_quota);
[...]
> +	return (budget - OSM_NOB(pnob)->work_quota);
> +}

These lines appear to be redundant.

> --- /dev/null
> +++ b/drivers/net/benet/be_netif.c
[...]
> +/* Strings to print Link properties */
> +static char *link_speed[] = {
> +	"Invalid link Speed Value",
> +	"10 Mbps",
> +	"100 Mbps",
> +	"1 Gbps",
> +	"10 Gbps"
> +};
> +
> +static char *link_duplex[] = {
> +	"Invalid Duplex Value",
> +	"Half Duplex",
> +	"Full Duplex"
> +};
> 
> +static char *link_state[] = {
> +	"",
> +	"(active)"
> +};
> +
> +
> +void be_print_link_info(struct BE_LINK_STATUS *lnk_status)
> +{
> +	u16 si, di, ai;
> +
> +	/* Port 0 */
> +	if (lnk_status->mac0_speed && lnk_status->mac0_duplex) {
> +		/* Port is up and running */
> +		si = (lnk_status->mac0_speed < 5) ?
> +			lnk_status->mac0_speed : 0;
> +		di = (lnk_status->mac0_duplex < 3) ?
> +			lnk_status->mac0_duplex : 0;
> +		ai = (lnk_status->active_port == 0) ?  1 : 0;
> +		printk(KERN_INFO "PortNo. 0: Speed - %s %s %s\n",
> +			link_speed[si], link_duplex[di], link_state[ai]);
> +	} else
> +		printk(KERN_INFO "PortNo. 0: Down\n");
> +
> +	/* Port 1 */
> +	if (lnk_status->mac1_speed && lnk_status->mac1_duplex) {
> +		/* Port is up and running */
> +		si = (lnk_status->mac1_speed < 5) ?
> +			lnk_status->mac1_speed : 0;
> +		di = (lnk_status->mac1_duplex < 3) ?
> +			lnk_status->mac1_duplex : 0;
> +		ai = (lnk_status->active_port == 0) ?  1 : 0;
> +		printk(KERN_INFO "PortNo. 1: Speed - %s %s %s\n",
> +			link_speed[si], link_duplex[di], link_state[ai]);
> +	} else
> +		printk(KERN_INFO "PortNo. 1: Down\n");
> +
> +	return;
> +}

Can't you leave this to ethtool and linkwatch?

> +/*
> + * Setting a Mac Address for BE
> + * Takes netdev and a void pointer as arguments.
> + * The pointer holds the new addres to be used.
> + */
> +static int benet_set_mac_addr(struct net_device *netdev, void *p)
> +{
> +	struct sockaddr *addr = p;
> +	struct bni_net_object *pnob;
> +	struct SA_MAC_ADDRESS mac_addr;
> +
> +	SA_ASSERT(netdev);
> +	pnob = (struct bni_net_object *) netdev->priv;
> +	SA_ASSERT(pnob);
> +
> +	memcpy(pnob->mac_address, addr->sa_data, netdev->addr_len);
> +	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
> +	memcpy(mac_addr.bytes, pnob->mac_address, SA_MAC_ADDRESS_SIZE);
> +	bni_set_uc_mac_adr(pnob, 0, 0, OSM_NOB(pnob)->devno,
> +			   &mac_addr, NULL, NULL);

Do you *really* need all these separate copies of the MAC address?

> +	/*
> +	 * Since we are doing Active-Passive failover, both
> +	 * ports should have matching MAC addresses everytime.
> +	 */
> +	bni_set_uc_mac_adr(pnob, 1, 0, OSM_NOB(pnob)->devno,
> +			   &mac_addr, NULL, NULL);
> +
> +	return 0;
> +}
> +
> +void get_stats_timer_handler(unsigned long context)
> +{
> +	struct be_timer_ctxt *ctxt = (struct be_timer_ctxt *) context;
> +
> +	if (atomic_read(&ctxt->get_stat_flag)) {
> +		atomic_dec(&ctxt->get_stat_flag);
> +		up((void *) ctxt->get_stat_sem);

get_stat_sem is declared as an unsigned long, so why are you treating it as
struct semaphore?

> +	}
> +	del_timer(&ctxt->get_stats_timer);
> +	return;
> +}

That's as far as I read.  I'll leave the rest for others.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ