xpp: PRI stability fixes

* We didn't handle proper E1/T1 transitions after device registration.

* Fix SPAN_REGISTERED(xpd):
  It now checks for DAHDI_FLAGBIT_REGISTERED as well, as this flag is
  set/clear by assign/unassign.

* From set_pri_proto():
  - Always free/allocate channels
  - Always call dahdi_init_span()

* Improve phonedev_cleanup() safety:
  - NULL pointers after free.
  - Zero number of channels at the end.

* Refactor channel allocation out of phonedev_init():
  - Into phonedev_alloc_channels()
  - Also called from xpd_init_span() to prevent duplicated logic.
  - And called from set_pri_proto() to prevent our bug.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
This commit is contained in:
Oron Peled 2013-12-29 13:43:14 -05:00 committed by Tzafrir Cohen
parent 06c45b7cd8
commit d4868092bf
3 changed files with 50 additions and 21 deletions

View File

@ -611,7 +611,7 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
} }
priv->pri_protocol = set_proto; priv->pri_protocol = set_proto;
priv->is_cas = -1; priv->is_cas = -1;
phonedev->channels = pri_num_channels(set_proto); phonedev_alloc_channels(xpd, pri_num_channels(set_proto));
phonedev->offhook_state = BITMASK(phonedev->channels); phonedev->offhook_state = BITMASK(phonedev->channels);
CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0);
priv->deflaw = deflaw; priv->deflaw = deflaw;
@ -1082,6 +1082,7 @@ static int pri_set_spantype(struct dahdi_span *span, enum spantypes spantype)
struct phonedev *phonedev = container_of(span, struct phonedev, span); struct phonedev *phonedev = container_of(span, struct phonedev, span);
xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev);
enum pri_protocol set_proto = PRI_PROTO_0; enum pri_protocol set_proto = PRI_PROTO_0;
int ret;
XPD_INFO(xpd, "%s: %s\n", __func__, dahdi_spantype2str(spantype)); XPD_INFO(xpd, "%s: %s\n", __func__, dahdi_spantype2str(spantype));
switch (spantype) { switch (spantype) {
@ -1099,7 +1100,13 @@ static int pri_set_spantype(struct dahdi_span *span, enum spantypes spantype)
__func__, dahdi_spantype2str(spantype)); __func__, dahdi_spantype2str(spantype));
return -EINVAL; return -EINVAL;
} }
return set_pri_proto(xpd, set_proto); ret = set_pri_proto(xpd, set_proto);
if (ret < 0) {
XPD_ERR(xpd, "%s: set_pri_proto failed\n", __func__);
return ret;
}
dahdi_init_span(span);
return 0;
} }
static int PRI_card_open(xpd_t *xpd, lineno_t pos) static int PRI_card_open(xpd_t *xpd, lineno_t pos)
@ -1929,7 +1936,8 @@ static void PRI_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack)
dchan_state(xpd, 0); dchan_state(xpd, 0);
} }
if (IS_SET(physical_mask, i)) { if (IS_SET(physical_mask, i)) {
r = XPD_CHAN(xpd, logical_chan)->readchunk; struct dahdi_chan *chan = XPD_CHAN(xpd, logical_chan);
r = chan->readchunk;
// memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG // memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG
memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE);
pcm += DAHDI_CHUNKSIZE; pcm += DAHDI_CHUNKSIZE;

View File

@ -458,29 +458,28 @@ static void phonedev_cleanup(xpd_t *xpd)
unsigned int x; unsigned int x;
for (x = 0; x < phonedev->channels; x++) { for (x = 0; x < phonedev->channels; x++) {
if (phonedev->chans[x]) if (phonedev->chans[x]) {
KZFREE(phonedev->chans[x]); KZFREE(phonedev->chans[x]);
if (phonedev->ec[x]) phonedev->chans[x] = NULL;
}
if (phonedev->ec[x]) {
KZFREE(phonedev->ec[x]); KZFREE(phonedev->ec[x]);
phonedev->ec[x] = NULL;
}
} }
phonedev->channels = 0;
} }
__must_check static int phonedev_init(xpd_t *xpd, int phonedev_alloc_channels(xpd_t *xpd, int channels)
const xproto_table_t *proto_table,
int channels, xpp_line_t no_pcm)
{ {
struct phonedev *phonedev = &PHONEDEV(xpd); struct phonedev *phonedev = &PHONEDEV(xpd);
int old_channels = phonedev->channels;
unsigned int x; unsigned int x;
spin_lock_init(&phonedev->lock_recompute_pcm); XPD_NOTICE(xpd, "Reallocating channels: %d -> %d\n",
old_channels, channels);
phonedev_cleanup(xpd);
phonedev->channels = channels; phonedev->channels = channels;
phonedev->no_pcm = no_pcm;
phonedev->offhook_state = 0x0; /* ONHOOK */
phonedev->phoneops = proto_table->phoneops;
phonedev->digital_outputs = 0;
phonedev->digital_inputs = 0;
atomic_set(&phonedev->dahdi_registered, 0);
atomic_set(&phonedev->open_counter, 0);
for (x = 0; x < phonedev->channels; x++) { for (x = 0; x < phonedev->channels; x++) {
if (! if (!
(phonedev->chans[x] = (phonedev->chans[x] =
@ -501,6 +500,29 @@ err:
phonedev_cleanup(xpd); phonedev_cleanup(xpd);
return -ENOMEM; return -ENOMEM;
} }
EXPORT_SYMBOL(phonedev_alloc_channels);
__must_check static int phonedev_init(xpd_t *xpd,
const xproto_table_t *proto_table,
int channels, xpp_line_t no_pcm)
{
struct phonedev *phonedev = &PHONEDEV(xpd);
spin_lock_init(&phonedev->lock_recompute_pcm);
phonedev->no_pcm = no_pcm;
phonedev->offhook_state = 0x0; /* ONHOOK */
phonedev->phoneops = proto_table->phoneops;
phonedev->digital_outputs = 0;
phonedev->digital_inputs = 0;
atomic_set(&phonedev->dahdi_registered, 0);
atomic_set(&phonedev->open_counter, 0);
if (phonedev_alloc_channels(xpd, channels) < 0)
goto err;
return 0;
err:
return -ENOMEM;
}
/* /*
* xpd_alloc - Allocator for new XPD's * xpd_alloc - Allocator for new XPD's
@ -1025,12 +1047,9 @@ EXPORT_SYMBOL(xpd_set_spanname);
static void xpd_init_span(xpd_t *xpd, unsigned offset, int cn) static void xpd_init_span(xpd_t *xpd, unsigned offset, int cn)
{ {
struct dahdi_span *span; struct dahdi_span *span;
int i;
memset(&PHONEDEV(xpd).span, 0, sizeof(struct dahdi_span)); memset(&PHONEDEV(xpd).span, 0, sizeof(struct dahdi_span));
for (i = 0; i < cn; i++) phonedev_alloc_channels(xpd, cn);
memset(XPD_CHAN(xpd, i), 0, sizeof(struct dahdi_chan));
span = &PHONEDEV(xpd).span; span = &PHONEDEV(xpd).span;
span->deflaw = DAHDI_LAW_MULAW; /* card_* drivers may override */ span->deflaw = DAHDI_LAW_MULAW; /* card_* drivers may override */
span->channels = cn; span->channels = cn;

View File

@ -38,6 +38,7 @@ xpd_t *xpd_alloc(xbus_t *xbus, int unit, int subunit, int subtype, int subunits,
int channels); int channels);
void xpd_free(xpd_t *xpd); void xpd_free(xpd_t *xpd);
void xpd_remove(xpd_t *xpd); void xpd_remove(xpd_t *xpd);
int phonedev_alloc_channels(xpd_t *xpd, int channels);
void update_xpd_status(xpd_t *xpd, int alarm_flag); void update_xpd_status(xpd_t *xpd, int alarm_flag);
const char *xpp_echocan_name(const struct dahdi_chan *chan); const char *xpp_echocan_name(const struct dahdi_chan *chan);
int xpp_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, int xpp_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
@ -64,6 +65,7 @@ void notify_rxsig(xpd_t *xpd, int pos, enum dahdi_rxsig rxsig);
extern struct proc_dir_entry *xpp_proc_toplevel; extern struct proc_dir_entry *xpp_proc_toplevel;
#endif #endif
#define SPAN_REGISTERED(xpd) atomic_read(&PHONEDEV(xpd).dahdi_registered) #define SPAN_REGISTERED(xpd) (atomic_read(&PHONEDEV(xpd).dahdi_registered) && \
test_bit(DAHDI_FLAGBIT_REGISTERED, &PHONEDEV(xpd).span.flags))
#endif /* XPP_DAHDI_H */ #endif /* XPP_DAHDI_H */