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:
parent
06c45b7cd8
commit
d4868092bf
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user