ipath_mad.c

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

C
1,571
字号
	if (set_overrunthreshold(dd, (ore & 0xF)))		goto err;	dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;	if (pip->clientrereg_resv_subnetto & 0x80) {		clientrereg = 1;		event.event = IB_EVENT_CLIENT_REREGISTER;		ib_dispatch_event(&event);	}	/*	 * Do the port state change now that the other link parameters	 * have been set.	 * Changing the port physical state only makes sense if the link	 * is down or is being set to down.	 */	state = pip->linkspeed_portstate & 0xF;	lstate = (pip->portphysstate_linkdown >> 4) & 0xF;	if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))		goto err;	/*	 * Only state changes of DOWN, ARM, and ACTIVE are valid	 * and must be in the correct state to take effect (see 7.2.6).	 */	switch (state) {	case IB_PORT_NOP:		if (lstate == 0)			break;		/* FALLTHROUGH */	case IB_PORT_DOWN:		if (lstate == 0)			if (get_linkdowndefaultstate(dd))				lstate = IPATH_IB_LINKDOWN_SLEEP;			else				lstate = IPATH_IB_LINKDOWN;		else if (lstate == 1)			lstate = IPATH_IB_LINKDOWN_SLEEP;		else if (lstate == 2)			lstate = IPATH_IB_LINKDOWN;		else if (lstate == 3)			lstate = IPATH_IB_LINKDOWN_DISABLE;		else			goto err;		ipath_set_linkstate(dd, lstate);		break;	case IB_PORT_ARMED:		ipath_set_linkstate(dd, IPATH_IB_LINKARM);		break;	case IB_PORT_ACTIVE:		ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);		break;	default:		/* XXX We have already partially updated our state! */		goto err;	}	ret = recv_subn_get_portinfo(smp, ibdev, port);	if (clientrereg)		pip->clientrereg_resv_subnetto |= 0x80;	goto done;err:	smp->status |= IB_SMP_INVALID_FIELD;	ret = recv_subn_get_portinfo(smp, ibdev, port);done:	return ret;}/** * rm_pkey - decrecment the reference count for the given PKEY * @dd: the infinipath device * @key: the PKEY index * * Return true if this was the last reference and the hardware table entry * needs to be changed. */static int rm_pkey(struct ipath_devdata *dd, u16 key){	int i;	int ret;	for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {		if (dd->ipath_pkeys[i] != key)			continue;		if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {			dd->ipath_pkeys[i] = 0;			ret = 1;			goto bail;		}		break;	}	ret = 0;bail:	return ret;}/** * add_pkey - add the given PKEY to the hardware table * @dd: the infinipath device * @key: the PKEY * * Return an error code if unable to add the entry, zero if no change, * or 1 if the hardware PKEY register needs to be updated. */static int add_pkey(struct ipath_devdata *dd, u16 key){	int i;	u16 lkey = key & 0x7FFF;	int any = 0;	int ret;	if (lkey == 0x7FFF) {		ret = 0;		goto bail;	}	/* Look for an empty slot or a matching PKEY. */	for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {		if (!dd->ipath_pkeys[i]) {			any++;			continue;		}		/* If it matches exactly, try to increment the ref count */		if (dd->ipath_pkeys[i] == key) {			if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) {				ret = 0;				goto bail;			}			/* Lost the race. Look for an empty slot below. */			atomic_dec(&dd->ipath_pkeyrefs[i]);			any++;		}		/*		 * It makes no sense to have both the limited and unlimited		 * PKEY set at the same time since the unlimited one will		 * disable the limited one.		 */		if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {			ret = -EEXIST;			goto bail;		}	}	if (!any) {		ret = -EBUSY;		goto bail;	}	for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {		if (!dd->ipath_pkeys[i] &&		    atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {			/* for ipathstats, etc. */			ipath_stats.sps_pkeys[i] = lkey;			dd->ipath_pkeys[i] = key;			ret = 1;			goto bail;		}	}	ret = -EBUSY;bail:	return ret;}/** * set_pkeys - set the PKEY table for port 0 * @dd: the infinipath device * @pkeys: the PKEY table */static int set_pkeys(struct ipath_devdata *dd, u16 *pkeys){	struct ipath_portdata *pd;	int i;	int changed = 0;	pd = dd->ipath_pd[0];	for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {		u16 key = pkeys[i];		u16 okey = pd->port_pkeys[i];		if (key == okey)			continue;		/*		 * The value of this PKEY table entry is changing.		 * Remove the old entry in the hardware's array of PKEYs.		 */		if (okey & 0x7FFF)			changed |= rm_pkey(dd, okey);		if (key & 0x7FFF) {			int ret = add_pkey(dd, key);			if (ret < 0)				key = 0;			else				changed |= ret;		}		pd->port_pkeys[i] = key;	}	if (changed) {		u64 pkey;		pkey = (u64) dd->ipath_pkeys[0] |			((u64) dd->ipath_pkeys[1] << 16) |			((u64) dd->ipath_pkeys[2] << 32) |			((u64) dd->ipath_pkeys[3] << 48);		ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n",			   (unsigned long long) pkey);		ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,				 pkey);	}	return 0;}static int recv_subn_set_pkeytable(struct ib_smp *smp,				   struct ib_device *ibdev){	u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);	__be16 *p = (__be16 *) smp->data;	u16 *q = (u16 *) smp->data;	struct ipath_ibdev *dev = to_idev(ibdev);	unsigned i, n = ipath_get_npkeys(dev->dd);	for (i = 0; i < n; i++)		q[i] = be16_to_cpu(p[i]);	if (startpx != 0 || set_pkeys(dev->dd, q) != 0)		smp->status |= IB_SMP_INVALID_FIELD;	return recv_subn_get_pkeytable(smp, ibdev);}#define IB_PMA_CLASS_PORT_INFO		__constant_htons(0x0001)#define IB_PMA_PORT_SAMPLES_CONTROL	__constant_htons(0x0010)#define IB_PMA_PORT_SAMPLES_RESULT	__constant_htons(0x0011)#define IB_PMA_PORT_COUNTERS		__constant_htons(0x0012)#define IB_PMA_PORT_COUNTERS_EXT	__constant_htons(0x001D)#define IB_PMA_PORT_SAMPLES_RESULT_EXT	__constant_htons(0x001E)struct ib_perf {	u8 base_version;	u8 mgmt_class;	u8 class_version;	u8 method;	__be16 status;	__be16 unused;	__be64 tid;	__be16 attr_id;	__be16 resv;	__be32 attr_mod;	u8 reserved[40];	u8 data[192];} __attribute__ ((packed));struct ib_pma_classportinfo {	u8 base_version;	u8 class_version;	__be16 cap_mask;	u8 reserved[3];	u8 resp_time_value;	/* only lower 5 bits */	union ib_gid redirect_gid;	__be32 redirect_tc_sl_fl;	/* 8, 4, 20 bits respectively */	__be16 redirect_lid;	__be16 redirect_pkey;	__be32 redirect_qp;	/* only lower 24 bits */	__be32 redirect_qkey;	union ib_gid trap_gid;	__be32 trap_tc_sl_fl;	/* 8, 4, 20 bits respectively */	__be16 trap_lid;	__be16 trap_pkey;	__be32 trap_hl_qp;	/* 8, 24 bits respectively */	__be32 trap_qkey;} __attribute__ ((packed));struct ib_pma_portsamplescontrol {	u8 opcode;	u8 port_select;	u8 tick;	u8 counter_width;	/* only lower 3 bits */	__be32 counter_mask0_9;	/* 2, 10 * 3, bits */	__be16 counter_mask10_14;	/* 1, 5 * 3, bits */	u8 sample_mechanisms;	u8 sample_status;	/* only lower 2 bits */	__be64 option_mask;	__be64 vendor_mask;	__be32 sample_start;	__be32 sample_interval;	__be16 tag;	__be16 counter_select[15];} __attribute__ ((packed));struct ib_pma_portsamplesresult {	__be16 tag;	__be16 sample_status;	/* only lower 2 bits */	__be32 counter[15];} __attribute__ ((packed));struct ib_pma_portsamplesresult_ext {	__be16 tag;	__be16 sample_status;	/* only lower 2 bits */	__be32 extended_width;	/* only upper 2 bits */	__be64 counter[15];} __attribute__ ((packed));struct ib_pma_portcounters {	u8 reserved;	u8 port_select;	__be16 counter_select;	__be16 symbol_error_counter;	u8 link_error_recovery_counter;	u8 link_downed_counter;	__be16 port_rcv_errors;	__be16 port_rcv_remphys_errors;	__be16 port_rcv_switch_relay_errors;	__be16 port_xmit_discards;	u8 port_xmit_constraint_errors;	u8 port_rcv_constraint_errors;	u8 reserved1;	u8 lli_ebor_errors;	/* 4, 4, bits */	__be16 reserved2;	__be16 vl15_dropped;	__be32 port_xmit_data;	__be32 port_rcv_data;	__be32 port_xmit_packets;	__be32 port_rcv_packets;} __attribute__ ((packed));#define IB_PMA_SEL_SYMBOL_ERROR			__constant_htons(0x0001)#define IB_PMA_SEL_LINK_ERROR_RECOVERY		__constant_htons(0x0002)#define IB_PMA_SEL_LINK_DOWNED			__constant_htons(0x0004)#define IB_PMA_SEL_PORT_RCV_ERRORS		__constant_htons(0x0008)#define IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS	__constant_htons(0x0010)#define IB_PMA_SEL_PORT_XMIT_DISCARDS		__constant_htons(0x0040)#define IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS	__constant_htons(0x0200)#define IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS	__constant_htons(0x0400)#define IB_PMA_SEL_PORT_VL15_DROPPED		__constant_htons(0x0800)#define IB_PMA_SEL_PORT_XMIT_DATA		__constant_htons(0x1000)#define IB_PMA_SEL_PORT_RCV_DATA		__constant_htons(0x2000)#define IB_PMA_SEL_PORT_XMIT_PACKETS		__constant_htons(0x4000)#define IB_PMA_SEL_PORT_RCV_PACKETS		__constant_htons(0x8000)struct ib_pma_portcounters_ext {	u8 reserved;	u8 port_select;	__be16 counter_select;	__be32 reserved1;	__be64 port_xmit_data;	__be64 port_rcv_data;	__be64 port_xmit_packets;	__be64 port_rcv_packets;	__be64 port_unicast_xmit_packets;	__be64 port_unicast_rcv_packets;	__be64 port_multicast_xmit_packets;	__be64 port_multicast_rcv_packets;} __attribute__ ((packed));#define IB_PMA_SELX_PORT_XMIT_DATA		__constant_htons(0x0001)#define IB_PMA_SELX_PORT_RCV_DATA		__constant_htons(0x0002)#define IB_PMA_SELX_PORT_XMIT_PACKETS		__constant_htons(0x0004)#define IB_PMA_SELX_PORT_RCV_PACKETS		__constant_htons(0x0008)#define IB_PMA_SELX_PORT_UNI_XMIT_PACKETS	__constant_htons(0x0010)#define IB_PMA_SELX_PORT_UNI_RCV_PACKETS	__constant_htons(0x0020)#define IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS	__constant_htons(0x0040)#define IB_PMA_SELX_PORT_MULTI_RCV_PACKETS	__constant_htons(0x0080)static int recv_pma_get_classportinfo(struct ib_perf *pmp){	struct ib_pma_classportinfo *p =		(struct ib_pma_classportinfo *)pmp->data;	memset(pmp->data, 0, sizeof(pmp->data));	if (pmp->attr_mod != 0)		pmp->status |= IB_SMP_INVALID_FIELD;	/* Indicate AllPortSelect is valid (only one port anyway) */	p->cap_mask = __constant_cpu_to_be16(1 << 8);	p->base_version = 1;	p->class_version = 1;	/*	 * Expected response time is 4.096 usec. * 2^18 == 1.073741824	 * sec.	 */	p->resp_time_value = 18;	return reply((struct ib_smp *) pmp);}/* * The PortSamplesControl.CounterMasks field is an array of 3 bit fields * which specify the N'th counter's capabilities. See ch. 16.1.3.2. * We support 5 counters which only count the mandatory quantities. */#define COUNTER_MASK(q, n) (q << ((9 - n) * 3))#define COUNTER_MASK0_9 \	__constant_cpu_to_be32(COUNTER_MASK(1, 0) | \			       COUNTER_MASK(1, 1) | \			       COUNTER_MASK(1, 2) | \			       COUNTER_MASK(1, 3) | \			       COUNTER_MASK(1, 4))static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,					   struct ib_device *ibdev, u8 port){	struct ib_pma_portsamplescontrol *p =		(struct ib_pma_portsamplescontrol *)pmp->data;	struct ipath_ibdev *dev = to_idev(ibdev);	unsigned long flags;	u8 port_select = p->port_select;	memset(pmp->data, 0, sizeof(pmp->data));	p->port_select = port_select;	if (pmp->attr_mod != 0 ||	    (port_select != port && port_select != 0xFF))		pmp->status |= IB_SMP_INVALID_FIELD;	/*	 * Ticks are 10x the link transfer period which for 2.5Gbs is 4	 * nsec.  0 == 4 nsec., 1 == 8 nsec., ..., 255 == 1020 nsec.  Sample	 * intervals are counted in ticks.  Since we use Linux timers, that	 * count in jiffies, we can't sample for less than 1000 ticks if HZ	 * == 1000 (4000 ticks if HZ is 250).	 */	/* XXX This is WRONG. */	p->tick = 250;		/* 1 usec. */	p->counter_width = 4;	/* 32 bit counters */	p->counter_mask0_9 = COUNTER_MASK0_9;	spin_lock_irqsave(&dev->pending_lock, flags);	p->sample_status = dev->pma_sample_status;	p->sample_start = cpu_to_be32(dev->pma_sample_start);	p->sample_interval = cpu_to_be32(dev->pma_sample_interval);	p->tag = cpu_to_be16(dev->pma_tag);	p->counter_select[0] = dev->pma_counter_select[0];	p->counter_select[1] = dev->pma_counter_select[1];	p->counter_select[2] = dev->pma_counter_select[2];	p->counter_select[3] = dev->pma_counter_select[3];	p->counter_select[4] = dev->pma_counter_select[4];	spin_unlock_irqrestore(&dev->pending_lock, flags);	return reply((struct ib_smp *) pmp);}static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,					   struct ib_device *ibdev, u8 port){	struct ib_pma_portsamplescontrol *p =		(struct ib_pma_portsamplescontrol *)pmp->data;	struct ipath_ibdev *dev = to_idev(ibdev);	unsigned long flags;	u32 start;	int ret;	if (pmp->attr_mod != 0 ||	    (p->port_select != port && p->port_select != 0xFF)) {		pmp->status |= IB_SMP_INVALID_FIELD;		ret = reply((struct ib_smp *) pmp);		goto bail;	}	start = be32_to_cpu(p->sample_start);	if (start != 0) {		spin_lock_irqsave(&dev->pending_lock, flags);		if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) {			dev->pma_sample_status =				IB_PMA_SAMPLE_STATUS_STARTED;			dev->pma_sample_start = start;			dev->pma_sample_interval =				be32_to_cpu(p->sample_interval);			dev->pma_tag = be16_to_cpu(p->tag);			if (p->counter_select[0])				dev->pma_counter_select[0] =					p->counter_select[0];			if (p->counter_select[1])				dev->pma_counter_select[1] =					p->counter_select[1];			if (p->counter_select[2])				dev->pma_counter_select[2] =					p->counter_select[2];			if (p->counter_select[3])				dev->pma_counter_select[3] =					p->counter_select[3];			if (p->counter_select[4])				dev->pma_counter_select[4] =					p->counter_select[4];		}		spin_unlock_irqrestore(&dev->pending_lock, flags);	}	ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port);bail:	return ret;}static u64 get_counter(struct ipath_ibdev *dev, __be16 sel){	u64 ret;	switch (sel) {	case IB_PMA_PORT_XMIT_DATA:		ret = dev->ipath_sword;		break;	case IB_PMA_PORT_RCV_DATA:		ret = dev->ipath_rword;		break;	case IB_PMA_PORT_XMIT_PKTS:		ret = dev->ipath_spkts;		break;	case IB_PMA_PORT_RCV_PKTS:		ret = dev->ipath_rpkts;		break;	case IB_PMA_PORT_XMIT_WAIT:		ret = dev->ipath_xmit_wait;		break;	default:		ret = 0;	}	return ret;}

⌨️ 快捷键说明

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