Skip to content

Commit b874405

Browse files
committed
Merge branch 's390-fixes'
Julian Wiedmann says: ==================== s390/qeth: fixes 2019-12-05 please apply the following fixes to your net tree. The first two patches target the RX data path, the third fixes a memory leak when shutting down a qeth device. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents a350d2e + f9e50b0 commit b874405

File tree

6 files changed

+119
-83
lines changed

6 files changed

+119
-83
lines changed

drivers/s390/net/qeth_core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ struct qeth_card_stats {
480480

481481
u64 rx_dropped_nomem;
482482
u64 rx_dropped_notsupp;
483+
u64 rx_dropped_runt;
483484

484485
/* rtnl_link_stats64 */
485486
u64 rx_packets;
@@ -627,6 +628,7 @@ struct qeth_ipato {
627628

628629
struct qeth_channel {
629630
struct ccw_device *ccwdev;
631+
struct qeth_cmd_buffer *active_cmd;
630632
enum qeth_channel_states state;
631633
atomic_t irq_pending;
632634
};
@@ -1037,6 +1039,8 @@ int qeth_do_run_thread(struct qeth_card *, unsigned long);
10371039
void qeth_clear_thread_start_bit(struct qeth_card *, unsigned long);
10381040
void qeth_clear_thread_running_bit(struct qeth_card *, unsigned long);
10391041
int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok);
1042+
int qeth_stop_channel(struct qeth_channel *channel);
1043+
10401044
void qeth_print_status_message(struct qeth_card *);
10411045
int qeth_init_qdio_queues(struct qeth_card *);
10421046
int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,

drivers/s390/net/qeth_core_main.c

Lines changed: 101 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,9 @@ static int __qeth_issue_next_read(struct qeth_card *card)
515515

516516
QETH_CARD_TEXT(card, 6, "noirqpnd");
517517
rc = ccw_device_start(channel->ccwdev, ccw, (addr_t) iob, 0, 0);
518-
if (rc) {
518+
if (!rc) {
519+
channel->active_cmd = iob;
520+
} else {
519521
QETH_DBF_MESSAGE(2, "error %i on device %x when starting next read ccw!\n",
520522
rc, CARD_DEVID(card));
521523
atomic_set(&channel->irq_pending, 0);
@@ -986,8 +988,21 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
986988
QETH_CARD_TEXT(card, 5, "data");
987989
}
988990

989-
if (qeth_intparm_is_iob(intparm))
990-
iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
991+
if (intparm == 0) {
992+
QETH_CARD_TEXT(card, 5, "irqunsol");
993+
} else if ((addr_t)intparm != (addr_t)channel->active_cmd) {
994+
QETH_CARD_TEXT(card, 5, "irqunexp");
995+
996+
dev_err(&cdev->dev,
997+
"Received IRQ with intparm %lx, expected %px\n",
998+
intparm, channel->active_cmd);
999+
if (channel->active_cmd)
1000+
qeth_cancel_cmd(channel->active_cmd, -EIO);
1001+
} else {
1002+
iob = (struct qeth_cmd_buffer *) (addr_t)intparm;
1003+
}
1004+
1005+
channel->active_cmd = NULL;
9911006

9921007
rc = qeth_check_irb_error(card, cdev, irb);
9931008
if (rc) {
@@ -1007,15 +1022,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
10071022
if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC))
10081023
channel->state = CH_STATE_HALTED;
10091024

1010-
if (intparm == QETH_CLEAR_CHANNEL_PARM) {
1011-
QETH_CARD_TEXT(card, 6, "clrchpar");
1012-
/* we don't have to handle this further */
1013-
intparm = 0;
1014-
}
1015-
if (intparm == QETH_HALT_CHANNEL_PARM) {
1016-
QETH_CARD_TEXT(card, 6, "hltchpar");
1017-
/* we don't have to handle this further */
1018-
intparm = 0;
1025+
if (iob && (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC |
1026+
SCSW_FCTL_HALT_FUNC))) {
1027+
qeth_cancel_cmd(iob, -ECANCELED);
1028+
iob = NULL;
10191029
}
10201030

10211031
cstat = irb->scsw.cmd.cstat;
@@ -1408,7 +1418,7 @@ static int qeth_clear_channel(struct qeth_card *card,
14081418

14091419
QETH_CARD_TEXT(card, 3, "clearch");
14101420
spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
1411-
rc = ccw_device_clear(channel->ccwdev, QETH_CLEAR_CHANNEL_PARM);
1421+
rc = ccw_device_clear(channel->ccwdev, (addr_t)channel->active_cmd);
14121422
spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
14131423

14141424
if (rc)
@@ -1430,7 +1440,7 @@ static int qeth_halt_channel(struct qeth_card *card,
14301440

14311441
QETH_CARD_TEXT(card, 3, "haltch");
14321442
spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
1433-
rc = ccw_device_halt(channel->ccwdev, QETH_HALT_CHANNEL_PARM);
1443+
rc = ccw_device_halt(channel->ccwdev, (addr_t)channel->active_cmd);
14341444
spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
14351445

14361446
if (rc)
@@ -1444,6 +1454,25 @@ static int qeth_halt_channel(struct qeth_card *card,
14441454
return 0;
14451455
}
14461456

1457+
int qeth_stop_channel(struct qeth_channel *channel)
1458+
{
1459+
struct ccw_device *cdev = channel->ccwdev;
1460+
int rc;
1461+
1462+
rc = ccw_device_set_offline(cdev);
1463+
1464+
spin_lock_irq(get_ccwdev_lock(cdev));
1465+
if (channel->active_cmd) {
1466+
dev_err(&cdev->dev, "Stopped channel while cmd %px was still active\n",
1467+
channel->active_cmd);
1468+
channel->active_cmd = NULL;
1469+
}
1470+
spin_unlock_irq(get_ccwdev_lock(cdev));
1471+
1472+
return rc;
1473+
}
1474+
EXPORT_SYMBOL_GPL(qeth_stop_channel);
1475+
14471476
static int qeth_halt_channels(struct qeth_card *card)
14481477
{
14491478
int rc1 = 0, rc2 = 0, rc3 = 0;
@@ -1746,6 +1775,8 @@ static int qeth_send_control_data(struct qeth_card *card,
17461775
spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
17471776
rc = ccw_device_start_timeout(channel->ccwdev, __ccw_from_cmd(iob),
17481777
(addr_t) iob, 0, 0, timeout);
1778+
if (!rc)
1779+
channel->active_cmd = iob;
17491780
spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
17501781
if (rc) {
17511782
QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n",
@@ -4667,12 +4698,12 @@ EXPORT_SYMBOL_GPL(qeth_vm_request_mac);
46674698

46684699
static void qeth_determine_capabilities(struct qeth_card *card)
46694700
{
4701+
struct qeth_channel *channel = &card->data;
4702+
struct ccw_device *ddev = channel->ccwdev;
46704703
int rc;
4671-
struct ccw_device *ddev;
46724704
int ddev_offline = 0;
46734705

46744706
QETH_CARD_TEXT(card, 2, "detcapab");
4675-
ddev = CARD_DDEV(card);
46764707
if (!ddev->online) {
46774708
ddev_offline = 1;
46784709
rc = ccw_device_set_online(ddev);
@@ -4711,7 +4742,7 @@ static void qeth_determine_capabilities(struct qeth_card *card)
47114742

47124743
out_offline:
47134744
if (ddev_offline == 1)
4714-
ccw_device_set_offline(ddev);
4745+
qeth_stop_channel(channel);
47154746
out:
47164747
return;
47174748
}
@@ -4911,9 +4942,9 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
49114942
QETH_DBF_MESSAGE(2, "Retrying to do IDX activates on device %x.\n",
49124943
CARD_DEVID(card));
49134944
rc = qeth_qdio_clear_card(card, !IS_IQD(card));
4914-
ccw_device_set_offline(CARD_DDEV(card));
4915-
ccw_device_set_offline(CARD_WDEV(card));
4916-
ccw_device_set_offline(CARD_RDEV(card));
4945+
qeth_stop_channel(&card->data);
4946+
qeth_stop_channel(&card->write);
4947+
qeth_stop_channel(&card->read);
49174948
qdio_free(CARD_DDEV(card));
49184949
rc = ccw_device_set_online(CARD_RDEV(card));
49194950
if (rc)
@@ -5028,27 +5059,15 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
50285059
}
50295060
EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card);
50305061

5031-
static void qeth_create_skb_frag(struct qdio_buffer_element *element,
5032-
struct sk_buff *skb, int offset, int data_len)
5062+
static void qeth_create_skb_frag(struct sk_buff *skb, char *data, int data_len)
50335063
{
5034-
struct page *page = virt_to_page(element->addr);
5064+
struct page *page = virt_to_page(data);
50355065
unsigned int next_frag;
50365066

5037-
/* first fill the linear space */
5038-
if (!skb->len) {
5039-
unsigned int linear = min(data_len, skb_tailroom(skb));
5040-
5041-
skb_put_data(skb, element->addr + offset, linear);
5042-
data_len -= linear;
5043-
if (!data_len)
5044-
return;
5045-
offset += linear;
5046-
/* fall through to add page frag for remaining data */
5047-
}
5048-
50495067
next_frag = skb_shinfo(skb)->nr_frags;
50505068
get_page(page);
5051-
skb_add_rx_frag(skb, next_frag, page, offset, data_len, data_len);
5069+
skb_add_rx_frag(skb, next_frag, page, offset_in_page(data), data_len,
5070+
data_len);
50525071
}
50535072

50545073
static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale)
@@ -5063,13 +5082,12 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
50635082
{
50645083
struct qdio_buffer_element *element = *__element;
50655084
struct qdio_buffer *buffer = qethbuffer->buffer;
5085+
unsigned int linear_len = 0;
50665086
int offset = *__offset;
50675087
bool use_rx_sg = false;
50685088
unsigned int headroom;
50695089
struct sk_buff *skb;
50705090
int skb_len = 0;
5071-
void *data_ptr;
5072-
int data_len;
50735091

50745092
next_packet:
50755093
/* qeth_hdr must not cross element boundaries */
@@ -5082,29 +5100,41 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
50825100
*hdr = element->addr + offset;
50835101

50845102
offset += sizeof(struct qeth_hdr);
5103+
skb = NULL;
5104+
50855105
switch ((*hdr)->hdr.l2.id) {
50865106
case QETH_HEADER_TYPE_LAYER2:
50875107
skb_len = (*hdr)->hdr.l2.pkt_length;
5108+
linear_len = ETH_HLEN;
50885109
headroom = 0;
50895110
break;
50905111
case QETH_HEADER_TYPE_LAYER3:
50915112
skb_len = (*hdr)->hdr.l3.length;
50925113
if (!IS_LAYER3(card)) {
50935114
QETH_CARD_STAT_INC(card, rx_dropped_notsupp);
5094-
skb = NULL;
50955115
goto walk_packet;
50965116
}
50975117

5118+
if ((*hdr)->hdr.l3.flags & QETH_HDR_PASSTHRU) {
5119+
linear_len = ETH_HLEN;
5120+
headroom = 0;
5121+
break;
5122+
}
5123+
5124+
if ((*hdr)->hdr.l3.flags & QETH_HDR_IPV6)
5125+
linear_len = sizeof(struct ipv6hdr);
5126+
else
5127+
linear_len = sizeof(struct iphdr);
50985128
headroom = ETH_HLEN;
50995129
break;
51005130
case QETH_HEADER_TYPE_OSN:
51015131
skb_len = (*hdr)->hdr.osn.pdu_length;
51025132
if (!IS_OSN(card)) {
51035133
QETH_CARD_STAT_INC(card, rx_dropped_notsupp);
5104-
skb = NULL;
51055134
goto walk_packet;
51065135
}
51075136

5137+
linear_len = skb_len;
51085138
headroom = sizeof(struct qeth_hdr);
51095139
break;
51105140
default:
@@ -5117,8 +5147,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
51175147
return NULL;
51185148
}
51195149

5120-
if (!skb_len)
5121-
return NULL;
5150+
if (skb_len < linear_len) {
5151+
QETH_CARD_STAT_INC(card, rx_dropped_runt);
5152+
goto walk_packet;
5153+
}
51225154

51235155
use_rx_sg = (card->options.cq == QETH_CQ_ENABLED) ||
51245156
((skb_len >= card->options.rx_sg_cb) &&
@@ -5130,9 +5162,9 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
51305162
skb = qethbuffer->rx_skb;
51315163
qethbuffer->rx_skb = NULL;
51325164
} else {
5133-
unsigned int linear = (use_rx_sg) ? QETH_RX_PULL_LEN : skb_len;
5134-
5135-
skb = napi_alloc_skb(&card->napi, linear + headroom);
5165+
if (!use_rx_sg)
5166+
linear_len = skb_len;
5167+
skb = napi_alloc_skb(&card->napi, linear_len + headroom);
51365168
}
51375169

51385170
if (!skb)
@@ -5141,18 +5173,32 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
51415173
skb_reserve(skb, headroom);
51425174

51435175
walk_packet:
5144-
data_ptr = element->addr + offset;
51455176
while (skb_len) {
5146-
data_len = min(skb_len, (int)(element->length - offset));
5177+
int data_len = min(skb_len, (int)(element->length - offset));
5178+
char *data = element->addr + offset;
5179+
5180+
skb_len -= data_len;
5181+
offset += data_len;
51475182

5183+
/* Extract data from current element: */
51485184
if (skb && data_len) {
5149-
if (use_rx_sg)
5150-
qeth_create_skb_frag(element, skb, offset,
5151-
data_len);
5152-
else
5153-
skb_put_data(skb, data_ptr, data_len);
5185+
if (linear_len) {
5186+
unsigned int copy_len;
5187+
5188+
copy_len = min_t(unsigned int, linear_len,
5189+
data_len);
5190+
5191+
skb_put_data(skb, data, copy_len);
5192+
linear_len -= copy_len;
5193+
data_len -= copy_len;
5194+
data += copy_len;
5195+
}
5196+
5197+
if (data_len)
5198+
qeth_create_skb_frag(skb, data, data_len);
51545199
}
5155-
skb_len -= data_len;
5200+
5201+
/* Step forward to next element: */
51565202
if (skb_len) {
51575203
if (qeth_is_last_sbale(element)) {
51585204
QETH_CARD_TEXT(card, 4, "unexeob");
@@ -5166,9 +5212,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
51665212
}
51675213
element++;
51685214
offset = 0;
5169-
data_ptr = element->addr;
5170-
} else {
5171-
offset += data_len;
51725215
}
51735216
}
51745217

@@ -6268,7 +6311,8 @@ void qeth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
62686311
card->stats.rx_frame_errors +
62696312
card->stats.rx_fifo_errors;
62706313
stats->rx_dropped = card->stats.rx_dropped_nomem +
6271-
card->stats.rx_dropped_notsupp;
6314+
card->stats.rx_dropped_notsupp +
6315+
card->stats.rx_dropped_runt;
62726316
stats->multicast = card->stats.rx_multicast;
62736317
stats->rx_length_errors = card->stats.rx_length_errors;
62746318
stats->rx_frame_errors = card->stats.rx_frame_errors;

drivers/s390/net/qeth_core_mpc.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,6 @@ extern unsigned char IPA_PDU_HEADER[];
2929
#define QETH_TIMEOUT (10 * HZ)
3030
#define QETH_IPA_TIMEOUT (45 * HZ)
3131

32-
#define QETH_CLEAR_CHANNEL_PARM -10
33-
#define QETH_HALT_CHANNEL_PARM -11
34-
35-
static inline bool qeth_intparm_is_iob(unsigned long intparm)
36-
{
37-
switch (intparm) {
38-
case QETH_CLEAR_CHANNEL_PARM:
39-
case QETH_HALT_CHANNEL_PARM:
40-
case 0:
41-
return false;
42-
}
43-
return true;
44-
}
45-
4632
/*****************************************************************************/
4733
/* IP Assist related definitions */
4834
/*****************************************************************************/

drivers/s390/net/qeth_ethtool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static const struct qeth_stats card_stats[] = {
5151
QETH_CARD_STAT("rx0 SG page allocs", rx_sg_alloc_page),
5252
QETH_CARD_STAT("rx0 dropped, no memory", rx_dropped_nomem),
5353
QETH_CARD_STAT("rx0 dropped, bad format", rx_dropped_notsupp),
54+
QETH_CARD_STAT("rx0 dropped, runt", rx_dropped_runt),
5455
};
5556

5657
#define TXQ_STATS_LEN ARRAY_SIZE(txq_stats)

0 commit comments

Comments
 (0)