cxgb3_main.c

来自「linux 内核源代码」· C语言 代码 · 共 2,534 行 · 第 1/5 页

C
2,534
字号
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)#define CXGB3_ATTR_RW(name, val_expr, store_method) \CXGB3_SHOW(name, val_expr) \static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);static struct attribute *cxgb3_attrs[] = {	&dev_attr_cam_size.attr,	&dev_attr_nfilters.attr,	&dev_attr_nservers.attr,	NULL};static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,			    char *buf, int sched){	struct port_info *pi = netdev_priv(to_net_dev(d));	struct adapter *adap = pi->adapter;	unsigned int v, addr, bpt, cpt;	ssize_t len;	addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;	rtnl_lock();	t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);	if (sched & 1)		v >>= 16;	bpt = (v >> 8) & 0xff;	cpt = v & 0xff;	if (!cpt)		len = sprintf(buf, "disabled\n");	else {		v = (adap->params.vpd.cclk * 1000) / cpt;		len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);	}	rtnl_unlock();	return len;}static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,			     const char *buf, size_t len, int sched){	struct port_info *pi = netdev_priv(to_net_dev(d));	struct adapter *adap = pi->adapter;	unsigned int val;	char *endp;	ssize_t ret;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	val = simple_strtoul(buf, &endp, 0);	if (endp == buf || val > 10000000)		return -EINVAL;	rtnl_lock();	ret = t3_config_sched(adap, val, sched);	if (!ret)		ret = len;	rtnl_unlock();	return ret;}#define TM_ATTR(name, sched) \static ssize_t show_##name(struct device *d, struct device_attribute *attr, \			   char *buf) \{ \	return tm_attr_show(d, attr, buf, sched); \} \static ssize_t store_##name(struct device *d, struct device_attribute *attr, \			    const char *buf, size_t len) \{ \	return tm_attr_store(d, attr, buf, len, sched); \} \static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)TM_ATTR(sched0, 0);TM_ATTR(sched1, 1);TM_ATTR(sched2, 2);TM_ATTR(sched3, 3);TM_ATTR(sched4, 4);TM_ATTR(sched5, 5);TM_ATTR(sched6, 6);TM_ATTR(sched7, 7);static struct attribute *offload_attrs[] = {	&dev_attr_sched0.attr,	&dev_attr_sched1.attr,	&dev_attr_sched2.attr,	&dev_attr_sched3.attr,	&dev_attr_sched4.attr,	&dev_attr_sched5.attr,	&dev_attr_sched6.attr,	&dev_attr_sched7.attr,	NULL};static struct attribute_group offload_attr_group = {.attrs = offload_attrs };/* * Sends an sk_buff to an offload queue driver * after dealing with any active network taps. */static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb){	int ret;	local_bh_disable();	ret = t3_offload_tx(tdev, skb);	local_bh_enable();	return ret;}static int write_smt_entry(struct adapter *adapter, int idx){	struct cpl_smt_write_req *req;	struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);	if (!skb)		return -ENOMEM;	req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));	req->mtu_idx = NMTUS - 1;	/* should be 0 but there's a T3 bug */	req->iff = idx;	memset(req->src_mac1, 0, sizeof(req->src_mac1));	memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);	skb->priority = 1;	offload_tx(&adapter->tdev, skb);	return 0;}static int init_smt(struct adapter *adapter){	int i;	for_each_port(adapter, i)	    write_smt_entry(adapter, i);	return 0;}static void init_port_mtus(struct adapter *adapter){	unsigned int mtus = adapter->port[0]->mtu;	if (adapter->port[1])		mtus |= adapter->port[1]->mtu << 16;	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);}static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,			      int hi, int port){	struct sk_buff *skb;	struct mngt_pktsched_wr *req;	skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);	req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));	req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;	req->sched = sched;	req->idx = qidx;	req->min = lo;	req->max = hi;	req->binding = port;	t3_mgmt_tx(adap, skb);}static void bind_qsets(struct adapter *adap){	int i, j;	for_each_port(adap, i) {		const struct port_info *pi = adap2pinfo(adap, i);		for (j = 0; j < pi->nqsets; ++j)			send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,					  -1, i);	}}#define FW_FNAME "t3fw-%d.%d.%d.bin"#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"static int upgrade_fw(struct adapter *adap){	int ret;	char buf[64];	const struct firmware *fw;	struct device *dev = &adap->pdev->dev;	snprintf(buf, sizeof(buf), FW_FNAME, FW_VERSION_MAJOR,		 FW_VERSION_MINOR, FW_VERSION_MICRO);	ret = request_firmware(&fw, buf, dev);	if (ret < 0) {		dev_err(dev, "could not upgrade firmware: unable to load %s\n",			buf);		return ret;	}	ret = t3_load_fw(adap, fw->data, fw->size);	release_firmware(fw);	if (ret == 0)		dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",			 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);	else		dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",			FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);		return ret;}static inline char t3rev2char(struct adapter *adapter){	char rev = 0;	switch(adapter->params.rev) {	case T3_REV_B:	case T3_REV_B2:		rev = 'b';		break;	case T3_REV_C:		rev = 'c';		break;	}	return rev;}static int update_tpsram(struct adapter *adap){	const struct firmware *tpsram;	char buf[64];	struct device *dev = &adap->pdev->dev;	int ret;	char rev;		rev = t3rev2char(adap);	if (!rev)		return 0;	snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,		 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);	ret = request_firmware(&tpsram, buf, dev);	if (ret < 0) {		dev_err(dev, "could not load TP SRAM: unable to load %s\n",			buf);		return ret;	}		ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);	if (ret)		goto release_tpsram;		ret = t3_set_proto_sram(adap, tpsram->data);	if (ret == 0)		dev_info(dev,			 "successful update of protocol engine "			 "to %d.%d.%d\n",			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);	else		dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",			TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);	if (ret)		dev_err(dev, "loading protocol SRAM failed\n");release_tpsram:	release_firmware(tpsram);		return ret;}/** *	cxgb_up - enable the adapter *	@adapter: adapter being enabled * *	Called when the first port is enabled, this function performs the *	actions necessary to make an adapter operational, such as completing *	the initialization of HW modules, and enabling interrupts. * *	Must be called with the rtnl lock held. */static int cxgb_up(struct adapter *adap){	int err;	int must_load;	if (!(adap->flags & FULL_INIT_DONE)) {		err = t3_check_fw_version(adap, &must_load);		if (err == -EINVAL) {			err = upgrade_fw(adap);			if (err && must_load)				goto out;		}		err = t3_check_tpsram_version(adap, &must_load);		if (err == -EINVAL) {			err = update_tpsram(adap);			if (err && must_load)				goto out;		}		err = t3_init_hw(adap, 0);		if (err)			goto out;		t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));		err = setup_sge_qsets(adap);		if (err)			goto out;		setup_rss(adap);		init_napi(adap);		adap->flags |= FULL_INIT_DONE;	}	t3_intr_clear(adap);	if (adap->flags & USING_MSIX) {		name_msix_vecs(adap);		err = request_irq(adap->msix_info[0].vec,				  t3_async_intr_handler, 0,				  adap->msix_info[0].desc, adap);		if (err)			goto irq_err;		if (request_msix_data_irqs(adap)) {			free_irq(adap->msix_info[0].vec, adap);			goto irq_err;		}	} else if ((err = request_irq(adap->pdev->irq,				      t3_intr_handler(adap,						      adap->sge.qs[0].rspq.						      polling),				      (adap->flags & USING_MSI) ?				       0 : IRQF_SHARED,				      adap->name, adap)))		goto irq_err;	enable_all_napi(adap);	t3_sge_start(adap);	t3_intr_enable(adap);	if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)		bind_qsets(adap);	adap->flags |= QUEUES_BOUND;out:	return err;irq_err:	CH_ERR(adap, "request_irq failed, err %d\n", err);	goto out;}/* * Release resources when all the ports and offloading have been stopped. */static void cxgb_down(struct adapter *adapter){	t3_sge_stop(adapter);	spin_lock_irq(&adapter->work_lock);	/* sync with PHY intr task */	t3_intr_disable(adapter);	spin_unlock_irq(&adapter->work_lock);	if (adapter->flags & USING_MSIX) {		int i, n = 0;		free_irq(adapter->msix_info[0].vec, adapter);		for_each_port(adapter, i)		    n += adap2pinfo(adapter, i)->nqsets;		for (i = 0; i < n; ++i)			free_irq(adapter->msix_info[i + 1].vec,				 &adapter->sge.qs[i]);	} else		free_irq(adapter->pdev->irq, adapter);	flush_workqueue(cxgb3_wq);	/* wait for external IRQ handler */	quiesce_rx(adapter);}static void schedule_chk_task(struct adapter *adap){	unsigned int timeo;	timeo = adap->params.linkpoll_period ?	    (HZ * adap->params.linkpoll_period) / 10 :	    adap->params.stats_update_period * HZ;	if (timeo)		queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);}static int offload_open(struct net_device *dev){	struct port_info *pi = netdev_priv(dev);	struct adapter *adapter = pi->adapter;	struct t3cdev *tdev = dev2t3cdev(dev);	int adap_up = adapter->open_device_map & PORT_MASK;	int err;	if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))		return 0;	if (!adap_up && (err = cxgb_up(adapter)) < 0)		return err;	t3_tp_set_offload_mode(adapter, 1);	tdev->lldev = adapter->port[0];	err = cxgb3_offload_activate(adapter);	if (err)		goto out;	init_port_mtus(adapter);	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,		     adapter->params.b_wnd,		     adapter->params.rev == 0 ?		     adapter->port[0]->mtu : 0xffff);	init_smt(adapter);	/* Never mind if the next step fails */	sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group);	/* Call back all registered clients */	cxgb3_add_clients(tdev);out:	/* restore them in case the offload module has changed them */	if (err) {		t3_tp_set_offload_mode(adapter, 0);		clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);		cxgb3_set_dummy_ops(tdev);	}	return err;}static int offload_close(struct t3cdev *tdev){	struct adapter *adapter = tdev2adap(tdev);	if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))		return 0;	/* Call back all registered clients */	cxgb3_remove_clients(tdev);	sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);	tdev->lldev = NULL;	cxgb3_set_dummy_ops(tdev);	t3_tp_set_offload_mode(adapter, 0);	clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);	if (!adapter->open_device_map)		cxgb_down(adapter);	cxgb3_offload_deactivate(adapter);	return 0;}static int cxgb_open(struct net_device *dev){	struct port_info *pi = netdev_priv(dev);	struct adapter *adapter = pi->adapter;	int other_ports = adapter->open_device_map & PORT_MASK;	int err;	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {		quiesce_rx(adapter);		return err;	}	set_bit(pi->port_id, &adapter->open_device_map);	if (is_offload(adapter) && !ofld_disable) {		err = offload_open(dev);		if (err)			printk(KERN_WARNING			       "Could not initialize offload capabilities\n");	}	link_start(dev);	t3_port_intr_enable(adapter, pi->port_id);	netif_start_queue(dev);	if (!other_ports)		schedule_chk_task(adapter);	return 0;}static int cxgb_close(struct net_device *dev){	struct port_info *pi = netdev_priv(dev);	struct adapter *adapter = pi->adapter;	t3_port_intr_disable(adapter, pi->port_id);	netif_stop_queue(dev);	pi->phy.ops->power_down(&pi->phy, 1);	netif_carrier_off(dev);	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?