Re: [PATCH 4/6] myri10ge - First half of the driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Brice Goglin <[email protected]> :
> [PATCH 4/6] myri10ge - First half of the driver
> 
> The first half of the myri10ge driver core.
> 
> Signed-off-by: Brice Goglin <[email protected]>
> Signed-off-by: Andrew J. Gallatin <[email protected]>
> 
>  myri10ge.c | 1483 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 1483 insertions(+)
> 
> --- /dev/null	2006-05-09 19:43:19.324446250 +0200
> +++ linux/drivers/net/myri10ge/myri10ge.c	2006-05-09 23:00:55.000000000 +0200
[...]
> +module_param(myri10ge_flow_control, int, S_IRUGO);
> +module_param(myri10ge_deassert_wait, int, S_IRUGO | S_IWUSR);
> +module_param(myri10ge_force_firmware, int, S_IRUGO);
> +module_param(myri10ge_skb_cross_4k, int, S_IRUGO | S_IWUSR);
> +module_param(myri10ge_initial_mtu, int, S_IRUGO);
> +module_param(myri10ge_napi, int, S_IRUGO);
> +module_param(myri10ge_napi_weight, int, S_IRUGO);
> +module_param(myri10ge_watchdog_timeout, int, S_IRUGO);
> +module_param(myri10ge_max_irq_loops, int, S_IRUGO);

MODULE_PARM_DESC() would be nice.

> +
> +#define MYRI10GE_FW_OFFSET 1024*1024
> +#define MYRI10GE_HIGHPART_TO_U32(X) \
> +(sizeof (X) == 8) ? ((uint32_t)((uint64_t)(X) >> 32)) : (0)
> +#define MYRI10GE_LOWPART_TO_U32(X) ((uint32_t)(X))
> +
> +#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
> +
> +int myri10ge_hyper_msi_cap_on(struct pci_dev *pdev)

static int ?

[...]
> +static int
> +myri10ge_send_cmd(struct myri10ge_priv *mgp, uint32_t cmd,
> +		  myri10ge_cmd_t *data)
> +{
> +	mcp_cmd_t *buf;
> +	char buf_bytes[sizeof(*buf) + 8];
> +	volatile mcp_cmd_response_t *response = mgp->cmd;
> +	volatile char __iomem *cmd_addr = mgp->sram + MYRI10GE_MCP_CMD_OFFSET;
> +	uint32_t dma_low, dma_high;
> +	int sleep_total = 0;
> +
> +	/* ensure buf is aligned to 8 bytes */
> +	buf = (mcp_cmd_t *) ((unsigned long)(buf_bytes + 7) & ~7UL);
> +
> +	buf->data0 = htonl(data->data0);
> +	buf->data1 = htonl(data->data1);
> +	buf->data2 = htonl(data->data2);
> +	buf->cmd = htonl(cmd);
> +	dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);
> +	dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);
> +
> +	buf->response_addr.low = htonl(dma_low);
> +	buf->response_addr.high = htonl(dma_high);
> +	spin_lock(&mgp->cmd_lock);
> +	response->result = 0xffffffff;
> +	mb();
> +	myri10ge_pio_copy((void __iomem *) cmd_addr, buf, sizeof (*buf));
> +
> +	/* wait up to 2 seconds */

You must not hold a spinlock for up to 2 seconds.

> +	for (sleep_total = 0; sleep_total < (2 * 1000); sleep_total += 10) {
> +		mb();
> +		if (response->result != 0xffffffff) {
> +			if (response->result == 0) {
> +				data->data0 = ntohl(response->data);
> +				spin_unlock(&mgp->cmd_lock);
> +				return 0;
> +			} else {
> +				dev_err(&mgp->pdev->dev,
> +					"command %d failed, result = %d\n",
> +				       cmd, ntohl(response->result));
> +				spin_unlock(&mgp->cmd_lock);
> +				return -ENXIO;

Return in a middle of a spinlock-intensive function. :o(

> +			}
> +		}
> +		udelay(1000 * 10);
> +	}
> +	spin_unlock(&mgp->cmd_lock);
> +	dev_err(&mgp->pdev->dev, "command %d timed out, result = %d\n",
> +	       cmd, ntohl(response->result));
> +	return -EAGAIN;
> +}
> +
> +
> +/*
> + * The eeprom strings on the lanaiX have the format
> + * SN=x\0
> + * MAC=x:x:x:x:x:x\0
> + * PT:ddd mmm xx xx:xx:xx xx\0
> + * PV:ddd mmm xx xx:xx:xx xx\0
> + */
> +int
> +myri10ge_read_mac_addr(struct myri10ge_priv *mgp)

static int ?

[...]
> +static void
> +myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
> +{
> +	volatile uint32_t *confirm;
> +	volatile char __iomem *submit;
> +	uint32_t buf[16];
> +	uint32_t dma_low, dma_high;
> +	int i;
> +
> +	/* clear confirmation addr */
> +	confirm = (volatile uint32_t *) mgp->cmd;
> +	*confirm = 0;
> +	mb();
> +
> +	/* send a rdma command to the PCIe engine, and wait for the
> +	 * response in the confirmation address.  The firmware should
> +	 * write a -1 there to indicate it is alive and well
> +	 */
> +	dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);
> +	dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);
> +
> +	buf[0] = htonl(dma_high); 	/* confirm addr MSW */
> +	buf[1] = htonl(dma_low); 	/* confirm addr LSW */
> +	buf[2] = htonl(0xffffffff);	/* confirm data */
> +	buf[3] = htonl(dma_high); 	/* dummy addr MSW */
> +	buf[4] = htonl(dma_low); 	/* dummy addr LSW */
> +	buf[5] = htonl(enable);		/* enable? */
> +
> +	submit = mgp->sram + 0xfc01c0;
> +
> +	myri10ge_pio_copy((void __iomem *) submit, &buf, sizeof (buf));
> +	mb();
> +	udelay(1000);
> +	mb();
> +	i = 0;
> +	while (*confirm != 0xffffffff && i < 20) {
> +		udelay(1000);
> +		i++;
> +	}

	for (i = 0; *confirm != 0xffffffff && i < 20; i++)
		udelay(1000);


[...]
> +static int
> +myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
> +{
> +	mcp_gen_header_t *hdr;
> +	struct device *dev = &mgp->pdev->dev;
> +	size_t bytes, hdr_offset;
> +	int status;
> +
> +	/* find running firmware header */
> +	hdr_offset = ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET));
> +
> +	if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) {
> +		dev_err(dev, "Running firmware has bad header offset (%d)\n",
> +			(int)hdr_offset);
> +		return -EIO;
> +	}
> +
> +	/* copy header of running firmware from SRAM to host memory to
> +	 * validate firmware */
> +	bytes = sizeof (mcp_gen_header_t);

const size_t bytes = ...

> +	hdr = (mcp_gen_header_t *) kmalloc(bytes, GFP_KERNEL);

Useless cast.

[...]
> +static int
> +myri10ge_change_pause(struct myri10ge_priv *mgp, int pause)
> +{
> +	myri10ge_cmd_t cmd;
> +	int status;
> +
> +	if (pause)
> +		status = myri10ge_send_cmd(mgp, MYRI10GE_MCP_ENABLE_FLOW_CONTROL, &cmd);
> +	else
> +		status = myri10ge_send_cmd(mgp, MYRI10GE_MCP_DISABLE_FLOW_CONTROL, &cmd);

	ctl = pause ? MYRI10GE_MCP_ENABLE_FLOW_CONTROL : 
		MYRI10GE_MCP_DISABLE_FLOW_CONTROL;

	status = myri10ge_send_cmd(mgp, ctl, ...)

> +
> +	if (status) {
> +		printk(KERN_ERR "myri10ge: %s: Failed to set flow control mode\n",
> +		       mgp->dev->name);
> +		return -ENXIO;

Why not use the status code returned by myri10ge_send_cmd() ?

[...]
> +static int
> +myri10ge_reset(struct myri10ge_priv *mgp)
> +{
[...]
> +	cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
> +	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
> +	cmd.data2 = len * 0x10001;
> +	status |= myri10ge_send_cmd(mgp, MYRI10GE_MCP_DMA_TEST, &cmd);

The status code is not used.

> +	mgp->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) /
> +		(cmd.data0 & 0xffff);
> +
> +	memset(mgp->rx_done.entry, 0, bytes);
> +
> +	/* reset mcp/driver shared state back to 0 */
> +	mgp->tx.req = 0;
> +	mgp->tx.done = 0;
> +	mgp->tx.pkt_start = 0;
> +	mgp->tx.pkt_done = 0;
> +	mgp->rx_big.cnt = 0;
> +	mgp->rx_small.cnt = 0;
> +	mgp->rx_done.idx = 0;
> +	mgp->rx_done.cnt = 0;
> +	status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
> +	myri10ge_change_promisc(mgp, 0);
> +	myri10ge_change_pause(mgp, mgp->pause);
> +	return status;
> +}
> +
> +static inline void
> +myri10ge_submit_8rx(mcp_kreq_ether_recv_t __iomem *dst, mcp_kreq_ether_recv_t *src)
> +{
> +	uint32_t low;
> +
> +	low = src->addr_low;
> +	src->addr_low = 0xffffffff;

DMA_32BIT_MASK ?

> +	myri10ge_pio_copy(dst, src, 8 * sizeof(*src));
> +	mb();
> +	src->addr_low = low;
> +	*(uint32_t __force *) &dst->addr_low = src->addr_low;
> +	mb();
> +}
> +
> +/*
> + * Set of routunes to get a new receive buffer.  Any buffer which
> + * crosses a 4KB boundary must start on a 4KB boundary due to PCIe
> + * wdma restrictions. We also try to align any smaller allocation to
> + * at least a 16 byte boundary for efficiency.  We assume the linux
> + * memory allocator works by powers of 2, and will not return memory
> + * smaller than 2KB which crosses a 4KB boundary.  If it does, we fall
> + * back to allocating 2x as much space as required.
> + */
> +
> +static inline struct sk_buff *
> +myri10ge_alloc_big(int bytes)

It fits on a single line.

> +{
> +	struct sk_buff *skb;
> +	unsigned long data, roundup;
> +
> +	skb = dev_alloc_skb(bytes + 4096 + MYRI10GE_MCP_ETHER_PAD);
> +	if (skb == NULL)
> +		return NULL;

Imho you will want to work directly with pages shortly.

[...]
> +static irqreturn_t
> +myri10ge_napi_intr(int irq, void *arg, struct pt_regs *regs)
> +{
> +	struct myri10ge_priv *mgp = (struct myri10ge_priv *) arg;

Useless cast.

[...]
> +static int
> +myri10ge_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
> +{
> +	return -EINVAL;
> +}

Useless.

-- 
Ueimor
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux