From d4868092bfdb9c6bdbdd38219c208139c70c44c7 Mon Sep 17 00:00:00 2001 From: Oron Peled Date: Sun, 29 Dec 2013 13:43:14 -0500 Subject: [PATCH] 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 --- drivers/dahdi/xpp/card_pri.c | 14 +++++++-- drivers/dahdi/xpp/xpp_dahdi.c | 53 ++++++++++++++++++++++++----------- drivers/dahdi/xpp/xpp_dahdi.h | 4 ++- 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/drivers/dahdi/xpp/card_pri.c b/drivers/dahdi/xpp/card_pri.c index 3630565..c586115 100644 --- a/drivers/dahdi/xpp/card_pri.c +++ b/drivers/dahdi/xpp/card_pri.c @@ -611,7 +611,7 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto) } priv->pri_protocol = set_proto; 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); CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); 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); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); enum pri_protocol set_proto = PRI_PROTO_0; + int ret; XPD_INFO(xpd, "%s: %s\n", __func__, dahdi_spantype2str(spantype)); switch (spantype) { @@ -1099,7 +1100,13 @@ static int pri_set_spantype(struct dahdi_span *span, enum spantypes spantype) __func__, dahdi_spantype2str(spantype)); 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) @@ -1929,7 +1936,8 @@ static void PRI_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack) dchan_state(xpd, 0); } 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 memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; diff --git a/drivers/dahdi/xpp/xpp_dahdi.c b/drivers/dahdi/xpp/xpp_dahdi.c index ffcd6dd..c0e441a 100644 --- a/drivers/dahdi/xpp/xpp_dahdi.c +++ b/drivers/dahdi/xpp/xpp_dahdi.c @@ -458,29 +458,28 @@ static void phonedev_cleanup(xpd_t *xpd) unsigned int x; for (x = 0; x < phonedev->channels; x++) { - if (phonedev->chans[x]) + if (phonedev->chans[x]) { KZFREE(phonedev->chans[x]); - if (phonedev->ec[x]) + phonedev->chans[x] = NULL; + } + if (phonedev->ec[x]) { KZFREE(phonedev->ec[x]); + phonedev->ec[x] = NULL; + } } + phonedev->channels = 0; } -__must_check static int phonedev_init(xpd_t *xpd, - const xproto_table_t *proto_table, - int channels, xpp_line_t no_pcm) +int phonedev_alloc_channels(xpd_t *xpd, int channels) { struct phonedev *phonedev = &PHONEDEV(xpd); + int old_channels = phonedev->channels; 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->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++) { if (! (phonedev->chans[x] = @@ -501,6 +500,29 @@ err: phonedev_cleanup(xpd); 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 @@ -1025,12 +1047,9 @@ EXPORT_SYMBOL(xpd_set_spanname); static void xpd_init_span(xpd_t *xpd, unsigned offset, int cn) { struct dahdi_span *span; - int i; memset(&PHONEDEV(xpd).span, 0, sizeof(struct dahdi_span)); - for (i = 0; i < cn; i++) - memset(XPD_CHAN(xpd, i), 0, sizeof(struct dahdi_chan)); - + phonedev_alloc_channels(xpd, cn); span = &PHONEDEV(xpd).span; span->deflaw = DAHDI_LAW_MULAW; /* card_* drivers may override */ span->channels = cn; diff --git a/drivers/dahdi/xpp/xpp_dahdi.h b/drivers/dahdi/xpp/xpp_dahdi.h index ab7df50..e50c283 100644 --- a/drivers/dahdi/xpp/xpp_dahdi.h +++ b/drivers/dahdi/xpp/xpp_dahdi.h @@ -38,6 +38,7 @@ xpd_t *xpd_alloc(xbus_t *xbus, int unit, int subunit, int subtype, int subunits, int channels); void xpd_free(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); const char *xpp_echocan_name(const struct dahdi_chan *chan); 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; #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 */