msm:sdio: channel close feature
The feature implement sdio_close() api call - synchronous with mdm
(sdio peer) close channel flow. The flow will clean pending rx packets
and leave the channel in close state.
NOTE: close for stream channels is not supported
Signed-off-by: Konstantin Dorfman <kdorfman@codeaurora.org>
diff --git a/arch/arm/mach-msm/sdio_al.c b/arch/arm/mach-msm/sdio_al.c
index 9ad8015..dfe3f68 100644
--- a/arch/arm/mach-msm/sdio_al.c
+++ b/arch/arm/mach-msm/sdio_al.c
@@ -146,6 +146,7 @@
#define SD_IO_RW_EXTENDED_QCOM 54
#define TIME_TO_WAIT_US 500
+#define SDIO_CLOSE_FLUSH_TIMEOUT_MSEC (10000)
#define SDIO_TEST_POSTFIX "_TEST"
@@ -389,12 +390,31 @@
unsigned int is_suspended;
int flashless_boot_on;
-
+ int ch_close_supported;
int state;
int (*lpm_callback)(void *, int);
};
/*
+ * Host operation:
+ * lower 16bits are operation code
+ * upper 16bits are operation state
+ */
+#define PEER_OPERATION(op_code , op_state) ((op_code) | ((op_state) << 16))
+#define GET_PEER_OPERATION_CODE(op) ((op) & 0xffff)
+#define GET_PEER_OPERATION_STATE(op) ((op) >> 16)
+
+enum peer_op_code {
+ PEER_OP_CODE_CLOSE = 1
+};
+
+enum peer_op_state {
+ PEER_OP_STATE_INIT = 0,
+ PEER_OP_STATE_START = 1
+};
+
+
+/*
* On the kernel command line specify
* sdio_al.debug_lpm_on=1 to enable the LPM debug messages
* By default the LPM debug messages are turned off
@@ -432,6 +452,7 @@
int func_num, int enable, u8 bit_offset);
static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name);
static void sdio_al_print_info(void);
+static int sdio_read_internal(struct sdio_channel *ch, void *data, int len);
#define SDIO_AL_ERR(func) \
do { \
@@ -736,8 +757,11 @@
/* Make sure we get interrupt for non-packet-mode right away */
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
struct sdio_channel *ch = &sdio_al_dev->channel[i];
- if ((!ch->is_valid) || (!ch->is_open))
+ if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
+ pr_debug(MODULE_NAME ":continue for channel %s in"
+ " state %d\n", ch->name, ch->state);
continue;
+ }
if (ch->is_packet_mode == false) {
ch->read_threshold = 1;
set_pipe_threshold(sdio_al_dev,
@@ -797,6 +821,7 @@
u32 overflow_pipe = 0;
u32 underflow_pipe = 0;
u32 thresh_intr_mask = 0;
+ int is_closing = 0;
if (sdio_al_dev->is_err) {
SDIO_AL_ERR(__func__);
@@ -860,12 +885,26 @@
u32 read_avail;
u32 new_packet_size = 0;
- if ((!ch->is_valid) || (!ch->is_open))
- continue;
+ if (ch->state == SDIO_CHANNEL_STATE_CLOSING)
+ is_closing = true; /* used to prevent sleep */
old_read_avail = ch->read_avail;
read_avail = mailbox->pipe_bytes_avail[ch->rx_pipe_index];
+ if ((ch->state == SDIO_CHANNEL_STATE_CLOSED) &&
+ (read_avail > 0)) {
+ /* Stop the timer to stop reading the mailbox */
+ sdio_al_dev->poll_delay_msec = 0;
+ pr_err(MODULE_NAME
+ ":Invalid read_avail 0x%x, old_read_avail=0x%x for CLOSED ch %s\n",
+ read_avail, old_read_avail, ch->name);
+ sdio_al_get_into_err_state(sdio_al_dev);
+ goto exit_err;
+ }
+ if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
+ (ch->state != SDIO_CHANNEL_STATE_CLOSING))
+ continue;
+
if (read_avail > INVALID_DATA_AVAILABLE) {
pr_err(MODULE_NAME
":Invalid read_avail 0x%x for pipe %d\n",
@@ -907,7 +946,8 @@
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
struct sdio_channel *ch = &sdio_al_dev->channel[i];
- if ((!ch->is_valid) || (!ch->is_open))
+ if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
+ (ch->state != SDIO_CHANNEL_STATE_CLOSING))
continue;
new_write_avail = mailbox->pipe_bytes_avail[ch->tx_pipe_index];
@@ -934,11 +974,12 @@
any_write_pending |=
(new_write_avail < ch->ch_config.max_tx_threshold);
}
-
+ /* notify clients */
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
struct sdio_channel *ch = &sdio_al_dev->channel[i];
- if ((!ch->is_valid) || (!ch->is_open) || (ch->notify == NULL))
+ if ((ch->state != SDIO_CHANNEL_STATE_OPEN) ||
+ (ch->notify == NULL))
continue;
if (rx_notify_bitmask & (1<<ch->num))
@@ -953,9 +994,12 @@
if ((rx_notify_bitmask == 0) && (tx_notify_bitmask == 0) &&
!any_read_avail && !any_write_pending) {
- DATA_DEBUG(MODULE_NAME ":Nothing to Notify for card %d\n",
- sdio_al_dev->card->host->index);
- if (is_inactive_time_expired(sdio_al_dev))
+ DATA_DEBUG(MODULE_NAME ":Nothing to Notify for card %d,"
+ " is_closing=%d\n",
+ sdio_al_dev->card->host->index, is_closing);
+ if (is_closing)
+ restart_inactive_time(sdio_al_dev);
+ else if (is_inactive_time_expired(sdio_al_dev))
sdio_al_sleep(sdio_al_dev, host);
} else {
DATA_DEBUG(MODULE_NAME ":Notify bitmask for card %d "
@@ -1514,11 +1558,14 @@
/* Verify test code compatibility with the modem */
sdioc_test_version = (header->version & 0xFF00) >> 8;
test_version = sdio_al->pdata->peer_sdioc_version_minor >> 8;
- if (test_version != sdioc_test_version)
+ if (test_version != sdioc_test_version) {
pr_err(MODULE_NAME ":HOST(0x%x) and CLIENT(0x%x) "
- "testing VERSION don't match, tests may fail\n",
+ "testing VERSION don't match\n",
test_version,
sdioc_test_version);
+ msleep(500);
+ BUG();
+ }
}
if ((header->signature != (u32) PEER_SDIOC_SW_MAILBOX_SIGNATURE) &&
@@ -1551,11 +1598,15 @@
goto exit_err;
}
}
+ sdio_al_dev->ch_close_supported = (header->version & 0x000F) >=
+ (sdio_al->pdata->peer_sdioc_version_minor & 0xF);
- pr_info(MODULE_NAME ":SDIOC SW version 0x%x\n", header->version);
+ pr_info(MODULE_NAME ":SDIOC SW version 0x%x, sdio_al major 0x%x"
+ " minor 0x%x\n", header->version,
+ sdio_al->sdioc_major,
+ sdio_al->pdata->peer_sdioc_version_minor);
sdio_al_dev->flashless_boot_on = false;
-
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
struct sdio_channel *ch = &sdio_al_dev->channel[i];
@@ -1569,6 +1620,10 @@
ch->num = i;
+ ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
+ ch->rx_pipe_index = ch->num*2;
+ ch->tx_pipe_index = ch->num*2+1;
+
memset(ch->name, 0, sizeof(ch->name));
if (header->channel_names[i][0]) {
@@ -1578,12 +1633,14 @@
header->channel_names[i],
PEER_CHANNEL_NAME_SIZE);
- ch->is_valid = 1;
+ ch->state = SDIO_CHANNEL_STATE_IDLE;
ch->sdio_al_dev = sdio_al_dev;
+ } else {
+ ch->state = SDIO_CHANNEL_STATE_INVALID;
}
- pr_info(MODULE_NAME ":Channel=%s, is_valid=%d\n", ch->name,
- ch->is_valid);
+ pr_info(MODULE_NAME ":Channel=%s, state=%d\n", ch->name,
+ ch->state);
}
return 0;
@@ -1637,13 +1694,6 @@
goto exit_err;
}
- pr_info(MODULE_NAME ":ch_config %s max_rx_threshold=%d.\n",
- ch->name, ch_config->max_rx_threshold);
- pr_info(MODULE_NAME ":ch_config %s max_tx_threshold=%d.\n",
- ch->name, ch_config->max_tx_threshold);
- pr_info(MODULE_NAME ":ch_config %s tx_buf_size=%d.\n",
- ch->name, ch_config->tx_buf_size);
-
/* Aggregation up to 90% of the maximum size */
ch->read_threshold = (ch_config->max_rx_threshold * 9) / 10;
/* Threshold on 50% of the maximum size , sdioc uses double-buffer */
@@ -1657,9 +1707,6 @@
ch->poll_delay_msec = DEFAULT_POLL_DELAY_NOPACKET_MSEC;
ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD_STREAMING;
}
- pr_info(MODULE_NAME ":ch %s is_packet_mode=%d.\n",
- ch->name, ch->is_packet_mode);
-
/* The max_packet_size is set by the modem in version 3 and on */
if (sdio_al->sdioc_major > PEER_SDIOC_OLD_VERSION_MAJOR)
ch->min_write_avail = ch_config->max_packet_size;
@@ -1667,14 +1714,12 @@
if (ch->min_write_avail > ch->write_threshold)
ch->min_write_avail = ch->write_threshold;
- pr_info(MODULE_NAME ":ch %s read_threshold=%d.\n",
- ch->name, ch->read_threshold);
- pr_info(MODULE_NAME ":ch %s write_threshold=%d.\n",
- ch->name, ch->write_threshold);
- pr_info(MODULE_NAME ":ch %s def_read_threshold=%d.\n",
- ch->name, ch->def_read_threshold);
- pr_info(MODULE_NAME ":ch %s min_write_avail=%d.\n",
- ch->name, ch->min_write_avail);
+ pr_info(MODULE_NAME ":ch %s read_threshold=%d, write_threshold=%d,"
+ " min_write_avail=%d, max_rx_threshold=%d,"
+ " max_tx_threshold=%d\n", ch->name, ch->read_threshold,
+ ch->write_threshold, ch->min_write_avail,
+ ch_config->max_rx_threshold,
+ ch_config->max_tx_threshold);
ch->peer_tx_buf_size = ch_config->tx_buf_size;
@@ -1939,7 +1984,8 @@
goto exit_err;
/* Set flag before interrupts are enabled to allow notify */
- ch->is_open = true;
+ ch->state = SDIO_CHANNEL_STATE_OPEN;
+ pr_debug(MODULE_NAME ":channel %s is in OPEN state now\n", ch->name);
sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
@@ -2085,7 +2131,6 @@
sdio_disable_func(wk_func);
goto error_exit;
}
-
sdio_disable_func(wk_func);
/* Start the timer again*/
@@ -2298,7 +2343,8 @@
continue;
sdio_al_dev = sdio_al->devices[j];
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- if (!sdio_al_dev->channel[i].is_valid)
+ if (sdio_al_dev->channel[i].state ==
+ SDIO_CHANNEL_STATE_INVALID)
continue;
if (strcmp(sdio_al_dev->channel[i].name, name) == 0) {
ch = &sdio_al_dev->channel[i];
@@ -2322,10 +2368,10 @@
int poll_delay_msec = 0x0FFFFFFF;
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
- if ((sdio_sl_dev->channel[i].is_valid) &&
- (sdio_sl_dev->channel[i].is_open) &&
- (sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
- (sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
+ if ((sdio_sl_dev->channel[i].state ==
+ SDIO_CHANNEL_STATE_OPEN) &&
+ (sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
+ (sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
poll_delay_msec =
sdio_sl_dev->channel[i].poll_delay_msec;
@@ -2366,8 +2412,9 @@
sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
- if (ch->is_open) {
- pr_err(MODULE_NAME ":Channel already opened %s\n", name);
+ if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
+ (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
+ pr_err(MODULE_NAME ":Wrong ch %s state %d\n", name, ch->state);
ret = -EPERM;
goto exit_err;
}
@@ -2423,18 +2470,202 @@
EXPORT_SYMBOL(sdio_open);
/**
+ * Request peer operation
+ * note: sanity checks of parameters done by caller
+ * called under bus locked
+ */
+static int peer_set_operation(u32 opcode,
+ struct sdio_al_device *sdio_al_dev,
+ struct sdio_channel *ch)
+{
+ int ret;
+ int offset;
+ struct sdio_func *wk_func;
+ u32 peer_operation;
+ int loop_count = 0;
+
+ wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
+ if (!wk_func) {
+ pr_err(MODULE_NAME ":%s: NULL wakeup func:%d\n",
+ __func__, SDIO_AL_WAKEUP_FUNC);
+ ret = -ENODEV;
+ goto exit;
+ }
+ /* calculate offset of peer_operation field in sw mailbox struct */
+ offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
+ sizeof(struct peer_sdioc_channel_config) * ch->num +
+ offsetof(struct peer_sdioc_channel_config, peer_operation);
+
+ ret = sdio_al_wake_up(sdio_al_dev, 1);
+ if (ret) {
+ pr_err(MODULE_NAME ":Fail to wake up\n");
+ goto exit;
+ }
+ /* request operation from MDM peer */
+ peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT);
+ ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
+ &peer_operation, sizeof(u32));
+ if (ret) {
+ pr_err(MODULE_NAME ":failed to request close operation\n");
+ goto exit;
+ }
+ ret = sdio_al_enable_func_retry(wk_func, "wk_func");
+ if (ret) {
+ pr_err(MODULE_NAME ":Fail to enable Func#%d\n", wk_func->num);
+ goto exit;
+ }
+ pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n",
+ __func__, ch->name);
+ /* send "start" operation to MDM */
+ peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START);
+ ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
+ &peer_operation, sizeof(u32));
+ if (ret) {
+ pr_err(MODULE_NAME ":failed to send start close operation\n");
+ goto exit;
+ }
+ ret = sdio_disable_func(wk_func);
+ if (ret) {
+ pr_err(MODULE_NAME ":Fail to disable Func#%d\n", wk_func->num);
+ goto exit;
+ }
+ /* poll for peer operation ack */
+ while (peer_operation != 0) {
+ ret = sdio_memcpy_fromio(ch->func,
+ &peer_operation,
+ SDIOC_SW_MAILBOX_ADDR+offset,
+ sizeof(u32));
+ if (ret) {
+ pr_err(MODULE_NAME ":failed to request ack on close"
+ " operation, loop_count = %d\n",
+ loop_count);
+ goto exit;
+ }
+ loop_count++;
+ if (loop_count > 10) {
+ pr_info(MODULE_NAME ":%s: peer_operation=0x%x wait loop"
+ " %d on ch %s\n", __func__,
+ peer_operation, loop_count, ch->name);
+ }
+ }
+exit:
+ return ret;
+}
+
+/**
* Close SDIO Channel.
*
*/
int sdio_close(struct sdio_channel *ch)
{
+ int ret;
+ struct sdio_al_device *sdio_al_dev = NULL;
+ void *temp_buf = NULL;
+ int flush_len;
+ ulong flush_expires;
+
if (!ch) {
pr_err(MODULE_NAME ":%s: NULL channel\n", __func__);
return -ENODEV;
}
- pr_debug(MODULE_NAME ":sdio_close is not supported\n");
+ sdio_al_dev = ch->sdio_al_dev;
+ if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ return -ENODEV;
- return -EPERM;
+ if (!sdio_al_dev->ch_close_supported || !ch->is_packet_mode) {
+ pr_info(MODULE_NAME ":%s: Not supported by mdm, ch %s\n",
+ __func__, ch->name);
+ return -ENOTSUPP;
+ }
+
+ if (!ch->func) {
+ pr_err(MODULE_NAME ":%s: NULL func on channel:%d\n",
+ __func__, ch->num);
+ return -ENODEV;
+ }
+ sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
+
+ if (sdio_al_dev->is_err) {
+ SDIO_AL_ERR(__func__);
+ sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ return -ENODEV;
+ }
+ if (sdio_al_dev->state != CARD_INSERTED) {
+ pr_err(MODULE_NAME ":%s: sdio_al_dev is in invalid state %d\n",
+ __func__, sdio_al_dev->state);
+ sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ return -ENODEV;
+ }
+ ch->state = SDIO_CHANNEL_STATE_CLOSING;
+ ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch);
+ if (ret) {
+ pr_err(MODULE_NAME ":%s: peer_set_operation() failed: %d\n",
+ __func__, ret);
+ sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ return -ENODEV;
+ }
+ /* udate poll time for opened channels */
+ if (ch->poll_delay_msec > 0) {
+ sdio_al_dev->poll_delay_msec =
+ get_min_poll_time_msec(sdio_al_dev);
+ }
+ sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+
+ flush_expires = jiffies +
+ msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
+ /* flush rx packets of the channel */
+ do {
+ while (ch->read_avail > 0) {
+ flush_len = ch->read_avail;
+ temp_buf = kzalloc(flush_len, GFP_KERNEL);
+ if (temp_buf == NULL) {
+ pr_err(MODULE_NAME ":%s failed to allocate"
+ " %d bytes during flush\n",
+ __func__, flush_len);
+ return -ENOMEM;
+ }
+ ret = sdio_read_internal(ch, temp_buf, flush_len);
+ kfree(temp_buf);
+ if (ret) {
+ pr_err(MODULE_NAME ":%s failed to"
+ " sdio_read: %d, ch %s\n",
+ __func__, ret, ch->name);
+ return ret;
+ }
+ if (jiffies > flush_expires) {
+ pr_err(MODULE_NAME ":%s flush rx packets"
+ " timeout: ch %s\n",
+ __func__, ch->name);
+ sdio_al_get_into_err_state(sdio_al_dev);
+ return -EBUSY;
+ }
+ }
+ msleep(100);
+ if (ch->signature != SDIO_AL_SIGNATURE) {
+ pr_err(MODULE_NAME ":%s: after sleep, invalid signature"
+ " 0x%x\n", __func__, ch->signature);
+ return -ENODEV;
+ }
+ } while (ch->read_avail > 0);
+
+ sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
+ /* disable channel interrupts */
+ enable_eot_interrupt(ch->sdio_al_dev, ch->rx_pipe_index, false);
+ enable_eot_interrupt(ch->sdio_al_dev, ch->tx_pipe_index, false);
+ enable_threshold_interrupt(ch->sdio_al_dev, ch->rx_pipe_index, false);
+ enable_threshold_interrupt(ch->sdio_al_dev, ch->tx_pipe_index, false);
+
+ /* disable function to be able to open the channel again */
+ ret = sdio_disable_func(ch->func);
+ if (ret) {
+ pr_err(MODULE_NAME ":Fail to disable Func#%d\n", ch->func->num);
+ sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ return ret;
+ }
+ ch->state = SDIO_CHANNEL_STATE_CLOSED;
+ sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+
+ return ret;
}
EXPORT_SYMBOL(sdio_close);
@@ -2453,7 +2684,11 @@
ch->signature);
return -ENODEV;
}
-
+ if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
+ pr_err(MODULE_NAME ":%s: channel %s state is not open (%d)\n",
+ __func__, ch->name, ch->state);
+ return -ENODEV;
+ }
pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n",
ch->name, ch->write_avail);
@@ -2476,23 +2711,26 @@
ch->signature);
return -ENODEV;
}
-
+ if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
+ pr_err(MODULE_NAME ":%s: channel %s state is not open (%d)\n",
+ __func__, ch->name, ch->state);
+ return -ENODEV;
+ }
pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n",
ch->name, ch->read_avail);
return ch->read_avail;
-
}
EXPORT_SYMBOL(sdio_read_avail);
/**
- * Read from SDIO Channel.
+ * Internal read from SDIO Channel.
*
* Reading from the pipe will trigger interrupt if there are
* other pending packets on the SDIO-Client.
*
*/
-int sdio_read(struct sdio_channel *ch, void *data, int len)
+static int sdio_read_internal(struct sdio_channel *ch, void *data, int len)
{
int ret = 0;
struct sdio_al_device *sdio_al_dev = NULL;
@@ -2550,9 +2788,10 @@
}
BUG_ON(sdio_al_dev->is_ok_to_sleep);
- if (!ch->is_open) {
- pr_err(MODULE_NAME ":reading from closed channel %s\n",
- ch->name);
+ if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
+ (ch->state != SDIO_CHANNEL_STATE_CLOSING)) {
+ pr_err(MODULE_NAME ":%s wrong channel %s state %d\n",
+ __func__, ch->name, ch->state);
sdio_release_host(sdio_al_dev->card->sdio_func[0]);
return -EINVAL;
}
@@ -2609,6 +2848,33 @@
return ret;
}
+
+/**
+ * Read from SDIO Channel.
+ *
+ * Reading from the pipe will trigger interrupt if there are
+ * other pending packets on the SDIO-Client.
+ *
+ */
+int sdio_read(struct sdio_channel *ch, void *data, int len)
+{
+ if (!ch) {
+ pr_err(MODULE_NAME ":%s: NULL channel\n", __func__);
+ return -ENODEV;
+ }
+ if (ch->signature != SDIO_AL_SIGNATURE) {
+ pr_err(MODULE_NAME ":%s: Invalid signature 0x%x\n", __func__,
+ ch->signature);
+ return -ENODEV;
+ }
+ if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
+ return sdio_read_internal(ch, data, len);
+ } else {
+ pr_err(MODULE_NAME ":%s: Invalid channel %s state %d\n",
+ __func__, ch->name, ch->state);
+ }
+ return -ENODEV;
+}
EXPORT_SYMBOL(sdio_read);
/**
@@ -2661,7 +2927,7 @@
return -ENODEV;
}
- if (!ch->is_open) {
+ if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
pr_err(MODULE_NAME ":writing to closed channel %s\n",
ch->name);
sdio_release_host(sdio_al_dev->card->sdio_func[0]);
@@ -2765,7 +3031,7 @@
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
int ch_name_size;
- if (!sdio_al_dev->channel[i].is_valid)
+ if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID)
continue;
if (sdio_al->unittest_mode) {
test_channel_init(sdio_al_dev->channel[i].name);
@@ -2793,14 +3059,16 @@
if (!sdio_al_dev->channel[i].pdev) {
pr_err(MODULE_NAME ":NULL platform device for ch %s",
sdio_al_dev->channel[i].name);
- sdio_al_dev->channel[i].is_valid = 0;
+ sdio_al_dev->channel[i].state =
+ SDIO_CHANNEL_STATE_INVALID;
continue;
}
ret = platform_device_add(sdio_al_dev->channel[i].pdev);
if (ret) {
pr_err(MODULE_NAME ":platform_device_add failed, "
"ret=%d\n", ret);
- sdio_al_dev->channel[i].is_valid = 0;
+ sdio_al_dev->channel[i].state =
+ SDIO_CHANNEL_STATE_INVALID;
}
}
@@ -3047,7 +3315,8 @@
"card %d\n",
__func__, card->host->index);
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- if (!sdio_al_dev->channel[i].is_valid)
+ if (sdio_al_dev->channel[i].state ==
+ SDIO_CHANNEL_STATE_INVALID)
continue;
platform_device_unregister(
sdio_al_dev->channel[i].pdev);
@@ -3179,9 +3448,8 @@
continue;
}
- if (!ch->is_valid) {
+ if (ch->state == SDIO_CHANNEL_STATE_INVALID)
continue;
- }
ch_config = &sdio_al_dev->channel[i].ch_config;
@@ -3196,13 +3464,6 @@
ch_config->max_packet_size,
ch->min_write_avail);
- if (!ch->is_open) {
- pr_err(MODULE_NAME
- ": %s is VALID but NOT OPEN. "
- "continuing...", ch->name);
- continue;
- }
-
pr_err(MODULE_NAME ": total_rx=0x%x, "
"total_tx=0x%x, "
"read_avail=0x%x, "
@@ -3419,7 +3680,8 @@
__func__, sdio_al_dev->card->host->index);
if (!sdio_al->unittest_mode)
for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
- if (!sdio_al_dev->channel[j].is_valid)
+ if (sdio_al_dev->channel[j].state
+ == SDIO_CHANNEL_STATE_INVALID)
continue;
platform_device_unregister(
sdio_al_dev->channel[j].pdev);